我无法理解以下代码的行为,我从C ++切片的示例中修改了这些代码:
#include <stdio.h>
#include <iostream>
struct B {
int x;
B() { x = 0; }
virtual void foo( const char* id ) {
std::cout << id << ": B=" << this << ", x=" << x << std::endl;
}
};
struct D1 : B {
int y;
D1() { x = 1; y = 100; }
virtual void foo( const char* id ) {
std::cout << id << ": D1=" << this << ", x=" << x << ", y=" << y << std::endl;
}
} d1;
struct D2 : B {
int z;
D2() { x = 2; z = 200; }
virtual void foo( const char* id ) {
std::cout << id << ": D2=" << this << ", x=" << x << ", z=" << z << std::endl;
}
} d2;
void main() {
std::cout << "d1 = " << &d1 << std::endl;
std::cout << "d2 = " << &d2 << std::endl;
std::cout << "By pointer at beginning: " << std::endl;
B* pb = &d1;
pb->foo( "pd1" );
pb = &d2;
pb->foo( "pd2" );
std::cout << "By Value: " << std::endl;
B b = d1;
b.foo( "d1" );
b = d2;
b.foo( "d2" );
std::cout << "By pointer after by value: " << std::endl;
pb = &d1;
pb->foo( "pd1" );
pb = &d2;
pb->foo( "pd2" );
std::cout << "By reference: " << std::endl;
B& rb = d1;
rb.foo( "rd1" );
rb = d2;
rb.foo( "rd2" );
std::cout << "By pointer after by reference: " << std::endl;
pb = &d1;
pb->foo( "pd1" );
pb = &d2;
pb->foo( "pd2" );
}
//The result is the following:
d1 = 0115B504
d2 = 0115B510
By pointer at beginning:
pd1: D1=0115B504, x=1, y=100
pd2: D2=0115B510, x=2, z=200
By Value:
d1: B=0036FE44, x=1
d2: B=0036FE44, x=2
By pointer after by value:
pd1: D1=0115B504, x=1, y=100
pd2: D2=0115B510, x=2, z=200
By reference:
rd1: D1=0115B504, x=1, y=100
rd2: D1=0115B504, x=2, y=100
By pointer after by reference:
pd1: D1=0115B504, x=2, y=100
pd2: D2=0115B510, x=2, z=200
从上面的结果中我们可以看到:
起初,我很惊讶您可以通过它们的基础为不同类型(D2到D1)分配引用,直到我意识到臭名昭着的C ++转换系统。一个结论似乎只能初始化参考但不能分配参考。
我们知道基础对象的STL容器有切片问题,因为除了list,所有其他STL容器复制对象。它看起来用于基础引用的STL容器应该更好,除非它将指针保存在内部。
你们如何处理这个问题?
谢谢! CP
答案 0 :(得分:2)
我发现在你的文字中很难找到一个问题,但我会假设它是这样的:
“如何在标准容器中以多态方式存储对象?”
首先,我要说的是,您无法在标准容器中存储引用,因为您无法分配(重新绑定)它们。
所以通常的方法是拥有一个基类指针容器。如果容器拥有这些项目,则使用unique_ptr
或shared_ptr
等智能指针。如果容器不拥有对象,那么只需使用原始指针。
答案 1 :(得分:1)
B& rb = d1;
rb.foo( "rd1" );
rb = d2;
最后一行与你写的
相同d1 = d2;
除了它仅适用于基类子对象。在第一行中,您将创建rb
的引用设置为具有不同静态类型的d1
的别名。参考不能重新安装。后面的赋值目标是对象。 d1直接只能使用其op =使用技巧来分配,但是你改变的静态类型使得Base :: op = work。
许多导师说你应该只使用抽象类作为基础,大多数推理都指向这样的事故。
在层次结构中,你很少有op = left,如果绝对需要你有一些虚拟的ssign来验证兼容性。