引用引起的C ++切片

时间:2013-06-14 18:06:16

标签: c++ stl pass-by-reference

我无法理解以下代码的行为,我从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

从上面的结果中我们可以看到:

  • 值赋值通过删除派生的特定成员导致切换问题到分配目标(b),但保留分配源(d1和d2)。
  • 引用分配通过不分配派生的特定成员导致切换到分配目标(rd),从而部分更改分配源(d1和d2)。

起初,我很惊讶您可以通过它们的基础为不同类型(D2到D1)分配引用,直到我意识到臭名昭着的C ++转换系统。一个结论似乎只能初始化参考但不能分配参考。

我们知道基础对象的STL容器有切片问题,因为除了list,所有其他STL容器复制对象。它看起来用于基础引用的STL容器应该更好,除非它将指针保存在内部。

你们如何处理这个问题?

谢谢! CP

2 个答案:

答案 0 :(得分:2)

我发现在你的文字中很难找到一个问题,但我会假设它是这样的:

  

“如何在标准容器中以多态方式存储对象?”

首先,我要说的是,您无法在标准容器中存储引用,因为您无法分配(重新绑定)它们。

所以通常的方法是拥有一个基类指针容器。如果容器拥有这些项目,则使用unique_ptrshared_ptr等智能指针。如果容器不拥有对象,那么只需使用原始指针。

答案 1 :(得分:1)

B& rb = d1;
rb.foo( "rd1" );
rb = d2;

最后一行与你写的

相同
d1 = d2;

除了它仅适用于基类子对象。在第一行中,您将创建rb的引用设置为具有不同静态类型的d1的别名。参考不能重新安装。后面的赋值目标是对象。 d1直接只能使用其op =使用技巧来分配,但是你改变的静态类型使得Base :: op = work。

许多导师说你应该只使用抽象类作为基础,大多数推理都指向这样的事故。

在层次结构中,你很少有op = left,如果绝对需要你有一些虚拟的ssign来验证兼容性。