【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派生类的构造函数
基类的构造函数不能被继承,在声明派生类时,对继承过来的成员变量的初始化工作也要由派生类的构造函数来完成.所以在设计派生类的构造函数时,不仅要考虑派生类新增的成员变量,还要考虑基类的成员变量,要让它们都 ...
随机推荐
- Web压力测试工具 LoadRunner12.x简易入门教程--(一)回放与录制
LoadRunner12.x简易入门教程--(一)回放与录制 今天在这里分享一下LoadRunner12.x版本的入门使用方法,希望对刚接触LoadRunner的童鞋有所帮助. LoadRun ...
- 第一节:从程序集的角度分析System.Web.Caching.Cache ,并完成基本封装。
一. 揭开迷雾 1. 程序集准备 a. 需要给项目添加 System.Web 程序集. b. 需要给使用的地方添加两个引用. 2. 程序集探究 在对应的类中输入关键字 Cache,选中点 ...
- Java图片比对
在自动化测试中,除了普通的值验证,经常还有一些图片验证,比如图片的匹配率,输出图片的差异图片等.本文主要用到了BufferedImage类来操作图片比对和输出差异图片,大体的思路如下: 1. 通过Im ...
- Linux - 账户切换授权
sudo 切换账户 echo myPassword | sudo -S ls /tmp # 直接输入sudo的密码非交互,从标准输入读取密码而不是终端设备 visudo # sudo命令权限添加 /e ...
- NOIP2018ty记
前置传送门:noip2018前流水账 Day-inf~Day-3 写流水账里了 懒得再写了 Day-2~Day-1 做了些noip的原题 真是奇怪,我天天爱跑步和逛公园都是1A的,结果反而有些普及组的 ...
- (原创 开源)AppWidge的使用—桌面便利贴
Android平台的一大特色就是支持桌面插件——AppWidget. 且不说,AppWidget是否会影响系统的流畅性,AppWidget确实是满足了用户个性化和快捷操作的需要. 常见的AppWidg ...
- websocket 工作原理
自己写一个websocket(教学用) import socket, base64, hashlib sock = socket.socket(socket.AF_INET, socket.SOCK_ ...
- python - 系统交互操作(subprocess)
本文摘于云游道士 链接:https://www.cnblogs.com/yyds/p/7288916.html 个人简化,便于查询. 命令行指令的执行通常有两个比较关注的结果: 命令执行的状态码--表 ...
- 数据库操作之整合Mybaties和事务讲解 5节课
1.SpringBoot2.x持久化数据方式介绍 简介:介绍近几年常用的访问数据库的方式和优缺点 1.原始java访问数据库 开发流程麻烦 ...
- python将图片转换为Framebuffer裸数据格式(终端显示图片)【转】
转自:https://www.cnblogs.com/zqb-all/p/6107905.html 要在ubuntu终端显示图片或者在板子的LCD显示图片,Framebuffer是一个简单易用的接口, ...