2

我对虚拟类和封装有一些问题。考虑以下 C++ 程序的最小示例:

#include <iostream>

class IConnection
{
    public:
        virtual void connect() = 0;
        virtual std::string recv() = 0;
        virtual void disconnect() = 0;
        virtual ~IConnection() {}
};


class ConcreteConnection: public IConnection
{
    public:
        ConcreteConnection(): m_connected(false) {}
        void connect() { m_connected = true; }
        std::string recv() { return "Received some text."; }
        void disconnect() { m_connected = false; }

    private:
        bool m_connected;

};

class Container
{
    public:
        Container() { m_connection = NULL; }
        void SetConnection(IConnection *connection) { m_connection = connection; };
        void GetData() { std::cout << m_connection->recv() << std::endl; }
        ~Container() { delete m_connection; }

    private:
        IConnection *m_connection;
};

int main(void)
{
    Container container;
    ConcreteConnection *connection = new ConcreteConnection();

    container.SetConnection(connection);
    container.GetData();

    return 0;
}

这个简单的例子效果很好,但我对此并不完全满意。容器对象应该拥有连接,而不受接口 IConnection 的具体实现的干扰。这就是我在容器外创建 ConcreteConnection 对象的原因。我不喜欢的是我必须传递连接的指针或引用。我想传递连接对象的副本,以便主函数在将连接对象传递给容器后没有任何机会操作或删除连接对象。但据我所知,如果不告诉容器它属于哪个 IConnection 的具体实现,就不可能传递连接的副本。

那么你知道如何解决这个问题吗?是否有可能将对象的副本传递给任何函数而不告诉函数该对象属于哪个接口的特定实现?

我对 C++ 和 OOP 都比较陌生,所以不要犹豫,告诉我,如果我的类结构完全错误,并且这种情况不会发生在现实生活中的编程代码中(以及它应该如何工作)。

提前致谢。

4

2 回答 2

2

这是我用现代 C++ 编写的方法:

#include <memory>
#include <type_traits>

class Container
{
    std::unique_ptr<IConnection> ptr;
    explicit Container(IConnection * p) : ptr(p) { }
public:
    template <typename T, typename ...Args>
    static typename std::enable_if<std::is_base_of<IConnection, T>::value, Container>::type
    make(Args &&... args)
    {
        return Container(new T(std::forward<Args>(args)...));
    }
};

用法:

int main()
{
    auto c1 = Container::make<ConcreteConnection>();
    auto c2 = Container::make<TCPConnection>("127.0.0.1", 8080);
    auto c3 = Container::make<LocalPipeConnection>("/tmp/pipe");
}
于 2013-06-14T19:38:54.770 回答
0

这样想:从抽象类继承的所有不同的具体类都有不同的成员,等等。所以除非你告诉编译器你正在传递什么样的对象,它怎么知道要分配多少内存等等.?

因此,当您编写一个将指向抽象类的指针作为参数的函数时,编译器确切地知道它需要为该参数分配多少空间:一个指针的大小。如果您尝试使参数成为抽象类的实例而不是指针,则编译器不知道要分配多少内存,因为它取决于将哪个派生类传递给函数。

于 2013-06-14T19:36:16.363 回答