虚拟接口和封装

时间:2013-06-14 19:27:35

标签: c++ class interface encapsulation virtual-method

虚拟类和封装存在一些问题。 请考虑以下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对象。我不喜欢的是 我必须传递连接的指针或引用。我想通过 connection-object的副本,因此main-function没有任何副本 在将连接对象传递给之后操纵或删除连接对象的机会 容器。但据我所知,不可能通过副本 连接,而不告诉容器具体实现 IConnection它属于。

那么你有什么想法解决这个问题吗?是否有可能传递一个 将对象复制到任何函数而不告诉函数到哪个 对象所属接口的具体实现?

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

提前致谢。

2 个答案:

答案 0 :(得分: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");
}

答案 1 :(得分:0)

以这种方式思考:从抽象类继承的所有不同的具体类都有不同的成员等。所以,除非你告诉编译器你传递了什么样的对象,它将如何知道有多少内存分配等?

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