为什么派生 class 的复制构造函数和重载=运算符不调用相应基 class 的复制构造函数和重载=运算符

why copy constructor and overloaded=operator of derived class not calling respective base class's copy constructor and overload=operator

.h

#ifndef header
#define header

struct base
{
    private:
        int p,q;
    public:
        base();
        base(const base&);              
        base operator=(const base&);    
        ~base();
};

struct der: public base
{
    private:    
        int x,y;
    public:
        
        der();
        der(const der&);
        der operator=(const der&);
        ~der();
}; 
#endif

.cpp

#include"10.h"
#include<iostream>

base::base()
{
    std::cout<<"base ctor- 0 arg\n";
    p=0; q=0;
}
base::base(const base &b)
{
    std::cout<<"base copy ctor\n";
    p=b.p;
    q=b.q;
}
base base::operator=(const base &b)
{
    std::cout<<"base overloaded=operator\n";
    p=b.p;
    q=b.q;
    return *this;
}
base::~base()
{
    std::cout<<"base dctor\n";
}


der::der()
{
    std::cout<<"derived ctor- 0 arg\n";
}
der::der(const der &d)
{
    std::cout<<"derived copy ctor\n";
    x=d.x;
    y=d.y;
    
}
der der::operator=(const der &d)
{
    std::cout<<"derived overloaded operator\n";
    x=d.x;
    y=d.y;
    return *this;
    
}
der::~der()
{
    std::cout<<"derived dctor\n";
}

主要

#include"10.h"
#include<iostream>
int main()
{
    der d1,d2;
    std::cout<<"\n";
    
    d2=d1;
    std::cout<<"\n";
    
    der d3=d1;
    std::cout<<"\n";
}

输出

base ctor- 0 arg
derived ctor- 0 arg
base ctor- 0 arg
derived ctor- 0 arg

derived overloaded operator
base ctor- 0 arg
derived copy ctor
derived dctor
base dctor

base ctor- 0 arg
derived copy ctor

derived dctor
base dctor
derived dctor
base dctor
derived dctor
base dctor

1. 当像我一样调用派生 class 的复制构造函数和重载 = 运算符时,base class 的 0-arg 构造函数如何调用没有创建任何基础 class 对象 ?

2. 为什么 overloaded=operator of derived class 不调用相应的 overloaded=operator of base class.

3. 与为什么派生的复制构造函数 class 不调用基 class.

的相应复制构造函数类似

下面我们一一分析主程序中的3条语句

我们将在最后讨论主程序中的第二条语句,因为这是需要最多解释的语句

语句 1:der d1, d2 这按预期工作,首先构造基础 class,然后为两个对象构造派生 class。

语句 3:der d3 = d1 这里我们试图从另一个 der class 对象 d1 复制构造一个 der class 对象 d3。 但是在构造派生 class 对象之前,首先需要创建基础 class 对象。 基类中有2个构造函数class,一个是默认构造函数,一个是复制构造函数,编译器会如何选择哪一个?

答案是我们需要告诉编译器选择哪个基础 class 构造函数,告诉它的方法是使用派生的 class 构造函数的初始化列表,并专门调用您希望使用的基础 class 构造函数。

der::der(const der &d):base(d)
{
    std::cout<<"derived copy ctor\n";
    x=d.x;
    y=d.y;
}

在上面的代码中,我们指定了如何构造基数 class。 d 引用将向上转换为 base class 引用以调用 base class 复制构造函数。

在您的原始版本中,编译器将需要一个默认的 base class 基类构造函数,而它正是被调用的,因为它没有指定如何构造基类 class.

语句 2:d2 = d1; 在此语句中,您正在调用赋值运算符,其定义为此处

der der::operator=(const der &d)
{
    std::cout<<"derived overloaded operator\n";
    x=d.x;
    y=d.y;
    return *this;
}

重载运算符只不过是函数,派生的 class 函数不会自动调用基础 class 函数。 如果您还需要调用基础 class 版本,那么您还需要在函数中添加调用的基础 class 版本,如下所示

der der::operator=(const der &d)
{
    base::operator=(d);
    std::cout<<"derived overloaded operator\n";
    x=d.x;
    y=d.y;
    return *this;
}

进行此更改后,现在还将调用基础 class operator=。 但是,如果您现在检查程序的输出,您会更加困惑。 该语句现在将产生的输出如下所示

base overloaded=operator
base copy ctor
base dctor
derived overloaded operator
base ctor- 0 arg
derived copy ctor
derived dctor
base dctor

为什么要调用这些构造函数和析构函数?

发生这种情况是因为 operator= function returns by value,这对于赋值运算符来说是不正确的。 在派生的 class 运算符的修改版本中,我们调用基 class 运算符 base::operator=(d); 该语句将调用下面的基础 class 运算符函数

base base::operator=(const base &b)
{
    std::cout<<"base overloaded=operator\n";
    p=b.p;
    q=b.q;
    return *this;
}

然而,这个函数 returns by value,这将导致基础 class 的一个临时对象被创建,然后它也将被立即销毁。 在此之后,派生的 class 运算符也按值 returns,这将需要构造一个 der class,而这又将需要一个基数 class 来被建造,然后这也将立即被摧毁。 导致我们看到的消息。

从 operator= 到 return 的正确方法是 returning 引用。 因此,将基础 class 和派生 class 运算符修改为如下 并且在.h文件中也做相应的修改。

base& base::operator=(const base &b)
{
    std::cout<<"base overloaded=operator\n";
    p=b.p;
    q=b.q;
    return *this;
}

der& der::operator=(const der &d)
{
    base::operator=(d);
    std::cout<<"derived overloaded operator\n";
    x=d.x;
    y=d.y;
    return *this;
}

一旦您将运算符函数修改为如上,第二条语句将打印如下。

base overloaded=operator
derived overloaded operator