派生类中默认(隐式)复制构造函数的c++行为

C++ behavior of a default(implicit) copy constructor in a derived class

本文关键字:构造函数 复制 c++ 行为 隐式 默认 派生      更新时间:2023-10-16

我有一个关于默认复制构造函数行为的问题。例如,这样的类:

class A{
public:
    A(){}
    A(const A& a){}
    ~A(){}
    void foo(){}
};
class B:public A{
    public:
    B(){}
    B(const B& b){}
    B& operator=(const B& b){return *this;}
    ~B(){}
    virtual void foo(){}
};
class C:public B{
public:
    C(){}
    C& operator=(const C& c){a_=c.a_; return *this;}
    ~C(){}
    void foo(){}
protected:
    A a_;
};

如果我将创建一个新的C类对象,如:

C* c1 = new C();

步骤如下:

  1. 通过显式A()创建A
  2. 通过显式B()创建B
  3. 通过显式A()创建A(类C中的受保护成员a_)
  4. 通过显式C()创建C

如果我将初始化C类的新对象,如:

    C c2(*c1);

将调用c的默认复制构造函数。据我所知,步骤如下:

    调用类C的隐式复制构造函数
  1. 显式调用A()。为什么不是A(const A& &;一)?
  2. 显式B(const B&b)。为什么不像基类A那样使用B()呢?
  3. 那么它最终会调用显式的A(const A&a) C类受保护成员a_。这次有什么不同?为什么现在是c'tor
  4. 的副本?
  5. 明确C&运算符= (const C&C)被召唤。为什么要调用operator=?据我所知,在初始化新对象时使用复制构造函数,而不是赋值操作符
  6. (const第一部;a)被称为a_ = c.a_(在C&运算符=)

默认复制构造函数的行为如何?它有什么规则?

我试图在互联网上搜索默认复制构造函数的实现,但我没有找到解释这种行为的东西。关于这个问题,谁能给点建议?

当您有一个派生类复制构造函数,如…

C(const C& c) {...}

你可能认为这会自动调用A和B的复制器,但它不会。隐含的行为就好像你写了…

C(const C& c) : B() {...}

…然后B的B()做了…

B() : A() {...}

如果你想要复制函数被调用到你的基类中,你需要显式地指定这种行为,像这样…

C(const C& c) : B(c) {...}

隐式生成的复制函数已经为你做了。

根据你的观察,operator=在你的情况下被称为,它不是。我不知道你为什么这么认为。

编译运行,检查代码中的注释,会更清楚:

#include <iostream>
class A{
public:
    A()
    {
    }
    A(const A& a)
    {
        std::cout << "Copy constructor FOR A is being called" << std::endl;
    }
    virtual ~A(){}
    void foo(){}
};
class B : public A
{
public:
    B()
    {
    }
    B(const B& b)
    {
        std::cout << "Copy constructor FOR B is being called" << std::endl;
    }
    B& operator=(const B& b){return *this;}
    virtual ~B()
    {
    }
    virtual void foo(){}
};
class C : public B
{
public:
    C()
    {
    }
    //if you remove this copy constructor, instead of only C being called, both A and B's copy constructor will be called
    C(const C& c)
    {
        std::cout << "Copy constructor FOR C is being called" << std::endl;
    }
    C& operator()(const C& c)
    {
        std::cout << "Operator is being called" << std::endl;
        a_=c.a_;
        return *this;
    }
    ~C()
    {
    }
    void foo()
    {
    }
protected:
    A a_;
};
int main()
{
    C* c = new C();
    C c2(*c); //copy constructor C will be called since we declared one, otherwise both A's and B's copy constructor would be called
    c2(c2); //here the operator() will be called but not above, changed that one to operator() since operator= didn't make sense
    delete c;
    std::cin.get();
    return 0;
}