提问人:Abhishek Mane 提问时间:7/7/2021 更新时间:7/7/2021 访问量:428
为什么复制构造函数和 overloaded=派生类的运算符不调用相应基类的复制构造函数和 overload=operator
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.当我没有创建任何基类对象时,基类的0-arg构造函数是如何调用的,因为我没有创建任何基类对象?
2. 为什么 overloaded=派生类的运算符不调用基类的相应 overloaded=运算符。
3.与为什么派生类的复制构造函数不调用基类的相应复制构造函数类似。
答:
让我们一一分析主程序中的 3 条语句。
我们将最后讨论主程序中的第二个语句,因为这是需要最大解释的语句
语句 1:der d1、d2这按预期工作,首先构造基类,然后为两个对象构造派生类。
语句 3:der d3 = d1在这里,我们尝试从另一个 der 类对象 d1 复制构造一个 der 类对象 d3。 但是,在构造派生类对象之前,首先需要创建基类对象。 基类中有 2 个构造函数,一个是默认构造函数,另一个是复制构造函数,编译器将如何选择哪一个?
答案是,我们需要告诉编译器要选择哪个基类构造函数,而判断这一点的方法是使用派生类构造函数的初始化列表,并专门调用您希望使用的基类构造函数。
der::der(const der &d):base(d)
{
std::cout<<"derived copy ctor\n";
x=d.x;
y=d.y;
}
在上面的代码中,我们指定了如何构造基类。d 引用将上调到基类引用,以便调用基类复制构造函数。
在原始版本中,编译器将需要基类的默认基类构造函数,并且确切地调用了该基类,因为它没有指定如何构造基类。
语句 2:d2 = d1;在此语句中,您将调用赋值运算符,其定义如下
der der::operator=(const der &d)
{
std::cout<<"derived overloaded operator\n";
x=d.x;
y=d.y;
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;
}
进行此更改后,现在还将调用基类 operator=。 但是,如果您现在检查程序的输出,它会让您更加困惑。 此语句现在将生成的输出如下所示
base overloaded=operator
base copy ctor
base dctor
derived overloaded operator
base ctor- 0 arg
derived copy ctor
derived dctor
base dctor
为什么调用这些构造函数和析构函数?
发生这种情况是因为 operator= 函数按值返回,这对赋值运算符来说不是正确的做法。 在派生类运算符的修改版本中,我们调用基类运算符 base::operator=(d);此语句将调用以下基类运算符函数
base base::operator=(const base &b)
{
std::cout<<"base overloaded=operator\n";
p=b.p;
q=b.q;
return *this;
}
但是,此函数按值返回,这将导致创建基类的临时对象,然后该对象也将立即被析构。 在此之后,派生类运算符也按值返回,这将需要构造一个 der 类,而 der 类又需要构造一个基类,然后该基类也将立即被销毁。 导致我们看到的消息。
从 operator= 返回的正确方法是返回引用。 因此,将基类和派生类运算符修改为如下 并在 .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
评论
copy constructor
overloaded=operator
copy constructor
overloaded=operator
下一个:继承的构造函数不能用于复制对象
评论
der::der(const der &d) : base(d) {/*..*/}
.operator=
只是一个成员函数;无论你写什么,它都会做。如果要调用基类版本,则必须自己调用它。派生类的构造函数将调用其基的构造函数,但如果 yo 未显式调用特定的构造函数,则编译器将生成调用默认构造函数的代码。