为什么派生 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
.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