【C++ Primer 第15章】定义派生类拷贝构造函数、赋值运算符
学习资料
• 派生类的赋值运算符/赋值构造函数也必须处理它的基类成员的赋值
定义拷贝构造函数
【注意】对派生类进行拷贝构造时,如果想让基类的成员也同时拷贝,就一定要在派生类拷贝构造函数初始化列表中显示调用基类拷贝构造函数(当然在函数体内将基类部分的值拷贝也是可以的,只不过它是先用默认构造函数初始化后再修改的基类成员变量的值,效率比较低),否则它会调用基类的默认构造函数,而不会对基类的成员变量拷贝值,这样生成的对象,它的派生类部分和被拷贝的对象派生类部分一样,而基类部分则是默认构造函数的初始化结果。
代码例子1:
#include <iostream>
using namespace std; class A
{
public:
A() { cout << "A default constructor" << endl; }
A(A&) { cout << "A copy constructor" << endl; }
};
class B : public A
{
public:
B() { cout << "A default constructor" << endl; }
B(B &b) { cout << "B copy constructor" << endl; }
}; int main()
{
B b;
B c = b;
return ;
}
输出结果:
代码例子2:
#include <iostream>
using namespace std; class A
{
public:
A() { cout << "A default constructor" << endl; }
A(A&) { cout << "A copy constructor" << endl; }
};
class B : public A
{
public:
B() { cout << "A default constructor" << endl; }
B(B &b) : A(b) { cout << "B copy constructor" << endl; }
}; int main()
{
B b;
B c = b;
return ;
}
输出结果:
C++ 基类构造函数带参数的继承方式及派生类的初始化
在定义类的时候,会遇到基类的构造函数带参数,而子类子类构造函数不带参数,这时候如果以代码 a 的方式建立派生类则会出错。
class A
{
public:
A(int x, int y): i(x), j(y) {}
private:
int i, j;
}; class B : public A
{
public:
B() { cout << "init B" << endl; }
};
在建立B类对象时,编译出错:
C:\Documents and Settings\admin\桌面\Text1.cpp() : error C2512: ‘A’ : no appropriate default constructor available
解决这个问题应该在A的构造函数中显式调用基类的带参构造函数。因为在基类中定义了带参构造函数,编译器不会提供默认构造函数。(或者可以在基类中增加一个不带参数的构造函数)这个问题将解决。
代码 b 采用的是调用基类带参构造函数的方式:
代码 b:
class A
{
public:
A(int x, int y): i(x), j(y) {}
private:
int i, j;
}; class B : public A
{
public:
B() A(,) { cout << "init B" << endl; }
};
通过在基类中增加一个不带参数的构造函数:
代码 c:
class A
{
public:
A(int x, int y): i(x), j(y) {}
A(); //不带参数的构造函数
private:
int i, j;
}; class B:public A
{
public:
B(): A(,) { cout << "init B" << endl; }
};
定义派生类赋值运算符
与拷贝和移动构造函数一样,派生类的赋值运算符也必须为其基类部分赋值。
// Base::operator=(const Base&) 不会被自动调用
D& D::operator=(const D &rhs)
{
Base::operator=(rhs); //为基类部分赋值
//按照过去的方式为派生类的成员赋值
return *this;
}
举例说明:
class base
{
public:
base(int initialvalue = ): x(initialvalue) {} private:
int x;
}; class derived : public base
{
public:
derived(int initialvalue): base(initialvalue), y(initialvalue) {}
derived& operator=(const derived& rhs); private:
int y;
}; 逻辑上说,derived的赋值运算符应该象这样:
derived& derived::operator = (const derived& rhs) // 错误的赋值运算符
{ // 请注意d1的base部分没有被赋值操作改变。
if (this == &rhs)
return *this;
y = rhs.y;
return *this;
} 不幸的是,它是错误的,因为derived对象的base部分的数据成员x在赋值运算符中未受影响。例如,考虑下面的代码段: void assignmenttester()
{
derived d1(); // d1.x = 0, d1.y = 0
derived d2(); // d2.x = 1, d2.y = 1 d1 = d2; // d1.x = 0, d1.y = 1
} derived& derived::operator = (const derived& rhs) // 正确的赋值运算符
{
if (this == &rhs)
return *this; base::operator = (rhs); // 调用this->base::operator=
y = rhs.y; return *this;
}
【C++ Primer 第15章】定义派生类拷贝构造函数、赋值运算符的更多相关文章
- 【【C++ Primer 第15章】 虚析构函数
学习资料 • C++中基类的析构函数为什么要用virtual虚析构函数 虚析构函数 1. 正文 直接的讲,C++中基类采用virtual虚析构函数是为了防止内存泄漏.具体地说,如果派生类中申请了内存空 ...
- C++学习之路—继承与派生(二):派生类的构造函数与析构函数
(根据<C++程序设计>(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明) 由于基类的构造函数和析构函数是不能被继承的,所以 ...
- C++:派生类的构造函数和析构函数
4.2 派生类的构造函数和析构函数4.2.1 派生类构造函数和析构函数的执行顺序 通常情况下,当创建派生类对象时,首先执行基类的构造函数,随后再执行派生类的构造函数:当撤销派生类对象时,则先执行派生类 ...
- 【C++ Primer 第15章】定义派生类析构函数
学习资料 • 基类和派生类析构函数执行顺序 定义派生类析构函数 [注意]定义一个对象时先调用基类的构造函数.然后调用派生类的构造函数:析构的时候恰好相反:先调用派生类的析构函数.然后调用基类的析构函数 ...
- [C++ Primer] : 第15章: 面向对象程序设计
OOP: 概述 面向对象程序设计的核心思想是数据抽象, 继承和动态绑定. 通过数据抽象, 我们可以实现类的接口与实现的分离; 使用继承, 可以定义相似的类型并对其相似关系建模; 使用动态绑定, 可以在 ...
- C++:派生类的构造函数和析构函数的调用顺序
一.派生类 在C++编程中,我们在编写一个基类的派生类时,大致可以分为四步: • 吸收基类的成员:不论是数据成员还是函数成员,派生类吸收除基类的构造函数和析构函数之外的全部成员. • 改造基类函数:在 ...
- c++ 派生类的构造函数 与 基类构造函数的关系
<面向对象程序设计基础(第二版>李师贤等,第254页:C++语言的基本规则是:创建一个派生类的对象时,如果基类带有构造函数,则先调用基类的构造函数,然后才调用派生类的构造函数. <T ...
- C++有子对象的派生类的构造函数
转载:https://blog.csdn.net/qq1169091731/article/details/50934588?utm_source=blogxgwz6 类的数据成员不但可以是标准型(如 ...
- C++学习17派生类的构造函数
基类的构造函数不能被继承,在声明派生类时,对继承过来的成员变量的初始化工作也要由派生类的构造函数来完成.所以在设计派生类的构造函数时,不仅要考虑派生类新增的成员变量,还要考虑基类的成员变量,要让它们都 ...
随机推荐
- python---redis中文操作与系统中文检测
import redis import chardet r.set("name","我是在Py3保存的中文字符串") ret = r.get("nam ...
- Dapper总结(一)---基本CRUD操作
一.dapper是什么 dapper是一款轻量级的ORM(Object Relationship Mapper),它负责数据库和编程语言之间的映射.SqlConnection,MysqlConnect ...
- Codeforces 15 E. Triangles
http://codeforces.com/problemset/problem/15/E 题意: 从H点走下去,再走回H点,不能走重复路径,且路径不能把黑色三角形包围的方案数 中间的黑色三角形把整张 ...
- git删除仓库的某个文件
可以用git rm命令删除文件(删除远程仓库文件) git clone 仓库地址 git add . git rm 文件//本地中该文件会被删除 git rm -r文件夹 //删除文件夹 上面会把对应 ...
- String类型的方法总结
String :字符串对象的包装类型 var stringObject = new String("wanglehui"); 方法总结: 1.返回该对象表示的基本字符串值(也就是返 ...
- Linux - 文件ACL权限控制
getfacl 1.test # 查看文件ACL权限 setfacl -R -m u:xuesong:rw- 1.test # 对文件增加用户的读写权限 -R 递归
- Java EE之Hibernate异常总结【2】Field 'id' doesn't have a default value
Field 'id' doesn't have a default value问题解决方法 因为assigned是指主键是由人工分配的,而native则指主键值由库自动给出. <generato ...
- 2018-2019-2 网络对抗技术 20165227 Exp2 后门原理与实践
2018-2019-2 网络对抗技术 20165227 Exp2 后门原理与实践 (1)例举你能想到的一个后门进入到你系统中的可能方式? 接收邮件的方式 (2)例举你知道的后门如何启动起来(win及l ...
- 发送http请求的方法
在http/1.1 协议中,定义了8种发送http请求的方法 get post options head put delete trace connect patch. 根据http协议的设计初衷,不 ...
- ubuntu下好用的音乐播放器audacious
audacious是ubuntu下一款非常好用的音乐播放器,万能的音乐播放器而且简洁美观,可以播放ape各种无损发烧音乐格式. 如果想听音乐的话,现在百度音乐,酷我音乐,酷狗音乐等都是有网络播放器的, ...