虚继承跳过构造函数
virtual inheritance - skipping constructors
我有以下类:
class Socket
{
Socket();
Socket( SOCKET s );
};
class Connection : public virtual Socket
{
Connection( IP ip );
};
这两个类包含一些纯虚函数和一些非虚函数,以及它们自己的一些数据。它们的意义在于,我将派生一些套接字类型,实现不同的协议。
所以我专门讲这两个类:
class ProtocolSocket : public virtual Socket
{
ProtocolSocket() {}
ProtocolSocket( SOCKET s ) : Socket( s ) { ; }
};
class ProtocolConnection : public ProtocolSocket, public virtual Connection
{
ProtocolConnection( SOCKET s, IP ip ) : ProtocolSocket( s ), Connection( ip ) {;}
};
事情出了问题——我相信你们很多人都能看到。我尝试创建一个协议连接:
new ProtocolConnection( s, ip );
构造过程如下:
start ctor ProtocolConnection
start ctor Connection
start ctor Socket
Socket(); - default ctor via Connection's init list
end ctor Socket
Connection(); - default ctor ProtocolConnection's init list
end ctor Connection
start ctor ProtocolSocket
start ctor Socket
// Socket( s ); - skipped!!! - would have been from init
// list of ProtocolSocket, but ctor for this object
// already called!
end ctor Socket
ProtocolSocket( s ); -from init list of ProtocolConnection()
end ctor ProtocolSocket
ProtocolConnection( s, ip );
end ctor ProtocolConnection
跳过第二个套接字构造函数是语言规范中规定的应该发生的事情,并且有很好的理由。
我如何使它调用构造函数与Socket(s)调用,而不是之前的一个?
我打算有多个派生类,如OtherProtocolSocket和OtherProcolConnection,在同一级别的ProtocoSocket和ProtocolConnection对象。
我想要实现的效果是我想要构造ProtocolSocket和ProtocolConnection对象,然后将它们作为Socket和Connection对象在我的系统中传递。因此,在我创建了实现给定协议的套接字之后,我只需对其进行读写,而不必担心底层协议的细节。
连接对象需要从Socket对象继承所有的方法。
@UPDATE:
建议在协议连接中增加套接字的初始化器。这就解决了问题。我愿意接受你的提议。但这只是一个评论
要记住的关键是,虚拟基类的构造函数是作为大多数派生类初始化的一部分完成的(并且在构造其他基类之前)。所以你的施工订单幻灯片是不正确的。
实际上,当您构造协议连接时,它首先构造套接字,然后是连接(因为您实际上继承了它),最后是ProtcolSocket。
要调用你想要的套接字的构造函数,你需要调用它的构造函数作为ProtocolSocket成员初始化列表的一部分,如下所示
class ProtocolConnection: public ProtocolSocket, public virtual Connection
{
public:
ProtocolConnection(int s, int ip) :
Socket(s), Connection(ip), ProtocolSocket(s)
// Note, also reordered, since all virtual bases are initialized before the
// non-virtual bases
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
最后,作为提示,我建议简化继承层次结构。特别是,虚拟继承和使用多个构造函数使因素复杂化。
继承:
ProtocolConnection
/
non-virtual virtual
/
ProtocolSocket Connection
| |
virtual virtual
| |
Socket Socket
注意,由于虚拟继承,在ProtocolConnection
类型的对象中只有一个Socket
子对象。
[class.base.init]/10
首先,并且仅对于最派生类的构造函数(1.8),虚拟基类按照它们在基类的有向无环图的深度优先的从左到右遍历中出现的顺序进行初始化,其中"从左到右"是基类在派生类基-指定符列表中出现的顺序。
虚拟基类的初始化是通过深度优先的从左到右遍历完成的。遍历顺序:
(0) ProtocolConnection
/
nv v
/
(1) ProtocolSocket (3) Connection
| |
v nv
| |
(2) Socket (4) Socket
导致初始化顺序为:
(2);(3);(1);(0) Socket
;Connection
;ProtocolSocket
(非虚基类);ProtocolConnection
派生最多的类ProtocolConnection
必须包含所有虚拟基类的初始化器。如果虚基类没有出现在最派生类的初始化列表中,则该虚基类的子对象将默认构造。
- 具有相同名称的类的构造函数继承
- 多复制构造函数继承中的惊人行为
- CRTP 和复制/移动赋值/构造函数继承
- 复制构造函数继承动态分配的数组
- 无法从 c++ 中的构造函数继承
- 在构造函数继承中使用默认构造函数
- 构造函数继承和直接成员初始化
- C++ - 使用私有参数的构造函数继承
- 通过可变参数模板进行C++11构造函数继承
- C++11构造函数继承和不带参数的构造函数
- C++11 - 构造函数继承
- C++构造函数继承
- 使用 C++11 编译器的构造函数继承正在生成错误
- 选择性构造函数继承"Ambiguous resolution"错误
- 什么是构造函数继承
- C++对象中的构造函数继承与方法继承
- C++构造函数继承没有匹配的函数
- C++构造函数继承(从派生类调用构造函数)
- 模板构造函数继承的标准符合语法是什么
- C++构造函数继承错误