在 C++ [duplicate] 的继承上下文中按值传递对象

Pass by value an object in context of inheritance in C++ [duplicate]

提问人:CSstudZ 提问时间:12/13/2019 最后编辑:CSstudZ 更新时间:12/13/2019 访问量:341

问:

我正在学习C++,在我老师的课程中,他解释说多态性与传递值不兼容。

他解释说,当你按值将对象传递给方法时,编译器会在堆栈中生成对象的副本,出于优化原因,他选择创建父类类型的副本。

例如,假设我有一个名为 A 的类,而类 B 是 A 的子类。 如果我按值传递一个 B 类型的对象,编译器会在堆栈上创建一个 A 类型的副本。

我的问题是:

  • 总是这样吗?

  • 假设我为类 B 创建了一个复制构造函数,那么当我将 B 类型的对象按值传递给方法时,编译器会使用它吗?或者它是否仍然将 B 复制为 A(对象切片)?如果不是,为什么?

谢谢!

编辑:示例

// in headers file
// for A
class A
{ 
    public :
        virtual void Display() const
         { cout << "A::Display() was called << endl; }
};

// for B
class B : public A
{ 
    public :
        void Display() const
         { cout << "B::Display() was called << endl; }
};

现在,另一个名为 main.cpp 的文件中有 3 种可能的情况:

案例 1:

void f( const A & anA)
{
    anA.Display();
}

int main() 
{
    B anB;
    f (anB);
    return 0;
}

案例 2:

void f( const A * anA)
{
    anA->Display();
}

int main() 
{
    A * anB = new B; 
    f ( anB );
    return 0;
}

案例 3:

void f( A anA)
{
    anA.Display();
}

int main() 
{
    B anB; 
    f ( anB );
    return 0;
}

据我了解,案例 1 和案例 2 将显示所需的输出(意思是“B::D isplay() 被调用”),而案例 3 不会(它将输出:“A::D isplay() was called”),即使 Display 方法在 A 类中被指定为 virtual。

C++ 对象 继承 编译器优化 按值传递

评论

2赞 Richard Critten 12/13/2019
这回答了你的问题吗?什么是对象切片?
0赞 CSstudZ 12/13/2019
@RichardCritten 谢谢。这无疑使对象切片更容易理解。但是,当涉及到通过值将对象(在继承上下文中)传递给方法时,我仍然对编译器优化感到困惑。
1赞 Richard Critten 12/13/2019
请为您的问题添加一个最小的可重复示例,以便我确信我理解您在问什么。
0赞 463035818_is_not_an_ai 12/13/2019
对象切片是将某些多态对象传递给函数时会发生什么情况的答案。您不需要对此进行优化
0赞 Davis Herring 12/13/2019
确切地说,切片并不是优化:只是在 C++ 中声明的对象(不是指针或引用)始终具有指定的类型。

答:

1赞 Richard Critten 12/13/2019 #1

案例(1)通过引用传递,不切片。

情况(2)按(指针的)值传递,不切片。

案例 (3) 按值传递:仅取顶部切片构建的复制。 没有部分。anAanBAanAB

与案例 (3) 相同的切片发生在这里:

B b;
A a = b;

我们创建一个并从中复制构造一个。BA

评论

0赞 CSstudZ 12/13/2019
好吧,我现在明白了。谢谢。另一个问题:您说过“anA 是从 anB 构造的复制”,因此如果我创建一个复制构造函数,我可以防止这种行为发生吗?
0赞 Richard Critten 12/13/2019
@CSstudZ SO 不鼓励每个问题超过 1 个问题(这会将网站变成论坛而不是问答网站)。如果您发布另一个问题,我很乐意尝试在那里回答。
0赞 Ted Lyngmo 12/30/2020
@CSstudZ 由于这个答案有助于您理解该主题,请考虑接受它。