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

Posted

技术标签:

【中文标题】在C ++中的继承上下文中按值传递对象[重复]【英文标题】:Pass by value an object in context of inheritance in C++ [duplicate] 【发布时间】:2020-04-06 06:27:20 【问题描述】:

我正在学习 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::Display() 被调用”),而案例 3 不会(它将输出:“A::Display () 被调用”),即使 Display 方法在 A 类中被指定为虚拟方法。

【问题讨论】:

这能回答你的问题吗? What is object slicing? @RichardCritten 谢谢。它肯定使对象切片更容易理解。但是,在将对象(在继承的上下文中)通过值传递给方法时,我仍然对编译器优化感到困惑到方法 请为您的问题添加minimal reproducible example,这样我确信我明白您在问什么。 对象切片是当你将一些多态对象传递给函数时发生的事情的答案。您不需要为此进行优化即可出错 发生切片并不是一种优化:只是在 C++ 中声明为这样的对象(而不是指针或引用)总是具有完全指定的类型。 【参考方案1】:

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

案例(2)传值(指针的)不切片。

案例(3)按值传递:anA 是从 anB 构造的副本,仅取顶部 A sliceanA 没有 B 部分。

这里发生与情况(3)相同的切片:

B b;
A a = b;

我们创建一个B 并从中复制构造一个A

【讨论】:

好的,我现在明白了。谢谢你。另一个问题:你说过“anA 是从 anB 构造的副本”,因此如果我创建一个复制构造函数,我可以防止这种行为发生吗? @CSstudZ SO 不鼓励每个问题超过 1 个问题(这会将网站变成论坛而不是问答网站)。如果您发布另一个问题,我很乐意尝试在那里回答。 @CSstudZ 因为这个答案帮助你理解了这个话题,请考虑接受它。

以上是关于在C ++中的继承上下文中按值传递对象[重复]的主要内容,如果未能解决你的问题,请参考以下文章

按值传递可变对象

为啥不允许将数组按值传递给 C 和 C++ 中的函数?

在 C++11 中按值或引用使用 lambda 默认捕获的缺点?

从函数返回对象时调用C ++中的复制构造函数?

js按值传递和按引用传递

C ++:将对象按值传递给同一类的成员函数