C++:赋值运算符和多重继承
【摘要】 在开源poco库的Socket类继承使用过程中,由于赋值运算符和多重继承出现了问题,因此模拟poco库源码写了一个测试用例,理解一下赋值运算符和多重继承等C++概念,如果有错误理解之处,请指出。
#include <iostream>
using namespace std;
class Socket
{
public:
Socket(int flags): _flags(flags){ cout << "Socket constructor" << " _flags pointer: " << &_flags << endl;}
Socket& operator = (const Socket& socket)
{
cout << "Socket assignment operationer. _flags = " << _flags << ", _flags pointer : " << &_flags << ", socket._flags = " << socket._flags << ", socket._flags pointer : " << &(socket._flags) << endl;
_flags = socket._flags;
return *this;
}
int getFlags() {
return _flags;
}
private:
int _flags = 0;
};
class StreamSocket: public Socket
{
public:
StreamSocket(): Socket(1){ cout << "StreamSocket(1) constructor" << endl; }
StreamSocket(int flags): Socket(flags) {cout << "StreamSocket(flags) constructor" << endl;}
StreamSocket& operator = (const Socket& socket)
{
cout << "StreamSocket assignment operationer" << endl;
Socket::operator = (socket);
return *this;
}
};
class SecureStreamSocket: public StreamSocket
{
public:
SecureStreamSocket(): StreamSocket(2){ cout << "SecureStreamSocket(2) constructor" << endl;}
SecureStreamSocket& operator = (const Socket& socket)
{
StreamSocket::operator = (socket);
cout << "SecureStreamSocket assignment operationer" << endl;
return *this;
}
};
class ZkStreamSocket: public StreamSocket
{
};
class ZkSecureStreamSocket : public ZkStreamSocket, public SecureStreamSocket
{
public:
using SecureStreamSocket::SecureStreamSocket;
};
/*
* 总结:
* 1:ZkSecureStreamSocket的内存分布包含了ZkStreamSocket和SecureStreamSocket两块,因此也包含了两块Socket和它的成员变量_flags;
* 2:由于赋值运算符不属于函数重写,其调用依赖于左值类型。同时,在调用赋值运算符的时候找不到参数匹配的赋值运算符,因此各个子类会生成
* 默认赋值运算符并且在默认赋值运算符中调用父类的赋值运算符。所以我们能看到最终调用到的都是Socket::operator =(Socket)(只要左值类
* 不是右值类的派生类);3:在test1和test2的对比中,多重继承的右值对象根据左值类型将内存中的对应的Socket::_flags在Socket类中拷贝
* 给左值。
*/
int main()
{
/*几个类中的赋值运算符看起来既不属于函数重载也不属于函数重写*/
/*test 1: https://stackoverflow.com/questions/8894090/derived-class-inherit-base-class-assignment-operator*/
/*反编译查看代码流程:https://www.cnblogs.com/skynet/archive/2010/09/05/1818636.html*/
ZkStreamSocket socket; // 菱形继承
cout << socket.getFlags() << endl; // 1
socket = ZkSecureStreamSocket(); // 改成ZkStreamSocket结果是一样的
cout << socket.getFlags() << endl; // 1
/*test 2*/
// SecureStreamSocket socket; // 菱形继承, 更改左值类型, 和上面结果对比,根据左值类型(基类作用域)进行子类给基类赋值(SecureStreamSocket和ZkStreamSocket是菱形继承的基类)?
// cout << socket.getFlags() << endl; // 2
// socket = ZkSecureStreamSocket();
// cout << socket.getFlags() << endl; // 2
/*test 3: https://www.codenong.com/cs106790463/*/
// StreamSocket socket; // 非菱形继承, 子类和父类互相赋值
// cout << socket.getFlags() << endl; // 1
// socket = SecureStreamSocket();
// cout << socket.getFlags() << endl; // 2
// return 0;
}
poco中在Socket部分代码中使用的是PIMPL(桥接),Socket类的Impl变量是“桥”,所有的其他派生类通过构造函数的方式将自己的Impl配置给Socket,其UML大概如下:
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)