C++_类继承6-继承和动态内存分配
如果基类使用动态内存分配,并重新定义赋值和复制构造函数,这将怎样影响派生类的实现?这个问题的答案取决于派生类的属性。如果派生类也使用动态内存分配,那就需要注意学习新的小技巧。
派生类不适用new
//Base Class Using DMA
class baseDMA
{
private:
char * label;
int rating;
public:
baseDMA(const char * l ="null", int r=0);
baseDMA(const baseDMA & rs);
virtual ~baseDMA();
base DMA & operator =(const baseDMA & rs);
...
};
//derived class without DMA
class lacksDMA : public baseDMA
{
private:
char color[40];
public:
...
}
派生类不适用new,不需要定义显式的析构函数,因为我们假设lackDMA成员不需执行任何特殊操作,所以默认析构函数时合适的。
复制构造函数:默认复制构造函数执行成员复制,这对于动态内存分配来说是不合适的,但对于新的lacksDMA成员来说是合适的。LacksDMA类的默认复制构造函数使用显式baseDMA复制构造函数来复制lackDMA对象的baseDMA部分。因此,默认复制构造函数对于新的lackDMA成员来说是合适的,同时对于继承的baseDMA对象来说也是合适的。
对于赋值来说,也是如此。类的默认赋值运算符将自动使用基类的赋值运算符对基类组件进行赋值。因此,默认赋值运算符也是合适的。
派生类对象的这些属性也适用于本身就是对象的类成员。
派生类使用new
这种情况下,必须为派生类定义显式析构函数,赋值构造函数和赋值运算符。
//derived class with DMA
class hasDMA:public baseDMA
{
private:
char * style;
public:
...
}
派生类析构函数自动调用基类的析构函数,故其自身的职责是对派生类构造函数执行工作的进行清理。因此,hasDMA析构函数必须释放指针style管理的内存,并依赖于baseDMA的析构函数来释放指针label管理的内存。
baseDMA::~baseDMA() // takes care of baseDMA stuff
{
delete [] label;
}
hasDMA::~hasDMA() // takes care of hasDMA stuff
{
delete [] style;
}
接下来看复制构造函数。BaseDMA的复制构造函数遵循用于
baseDMA::baseDMA(const baseDMA & rs)
{
label = new char[std::strlen(rs.label)+1];
std::strcpy(label,rs.label);
rating = rs.rating;
}
hasDMA复制构造函数只能访问hasDMA的数据,因此它必须调用baseDMA复制构造函数来处理共享的baseDMA数据:
hasDMA::hasDMA(const hasDMA & hs)
:baseDMA(hs)
{
style = new char[std::strlen(hs.style)+1];
std::strcpy(style, hs.style);
}
需要注意一点是,成员初始化列表将一个hasDMA引用传递给baseDMA构造函数。
接下来看赋值运算符。BaseDMA赋值运算符遵循下述常规模式:
baseDMA & baseDMA::operator=(const baseDMA & rs)
{
if (this == &rs)
return *this;
delete [] label;
label = new char[std::strlen(rs.label)+1];
std::strcpy(label, rs.label);
rating = rs.rating;
return *this;
}
hasDMA & hasDMA::operator=(const hasDMA & hs)
{
if(this == &hs)
return *this;
baseDMA::operator=(hs);
delete [] style;
style = new char[std::strlen(hs.style)+1];
std::strcpy(style,hs.style);
return *this;
}
以下语句看起来有点奇怪:
baseDMA::operator=(hs);
但通过使用函数表示法,而不是运算符表示法,可以使用作用域解析运算符。实际上该语句的含义如下:
*this = hs;
当基类和派生类都采用动态内存分配时,派生类的析构函数,复制构造函数,赋值运算符都必须使用相应的基类方法处理基类元素。
但这种要求是通过三种不同的方式来满足的。
对于析构函数:这是自动完成的;
对于构造函数:这是通过在初始化成员列表中调用基类的复制构造函数来完成的;
对于赋值运算符,这是通过使用作用域解析运算符显式地调用基类的赋值运算符来完成的;
C++_类继承6-继承和动态内存分配的更多相关文章
- C++之继承和动态内存分配
C++之继承和动态内存分配 如果基类使用动态内存分配,并重新定义赋值和复制构造函数,这将如何影响派生类的实现呢?这取决于派生类的属性,如果派生类也使用动态内存分配,这将如何实现呢?这种 ...
- C++解析(25):关于动态内存分配、虚函数和继承中强制类型转换的疑问
0.目录 1.动态内存分配 1.1 new和malloc的区别 1.2 delete和free的区别 2.虚函数 2.1 构造函数与析构函数是否可以成为虚函数? 2.2 构造函数与析构函数是否可以发生 ...
- C++_类和动态内存分配3-构造函数中使用new的注意事项
如果在构造函数中使用new来初始化对象的指针成员时必须特别小心. 1 如果在构造函数中使用new来初始化指针成员,则应在析构函数中使用delete. 2 new和delete必须相互兼容.new对应于 ...
- String类型_static成员_动态内存分配_拷贝构造函数_const关键字_友元函数与友元类
1:String类型 #include <iostream> using namespace std; int main() { //初始化方法 string s1 = "hel ...
- 《C++ Primer Plus》读书笔记之十—类和动态内存分配
第12章 类和动态内存分配 1.不能在类声明中初始化静态成员变量,这是因为声明描述了如何分配内存,但并不分配内存.可以在类声明之外使用单独的语句进行初始化,这是因为静态类成员是单独存储的,而不是对象的 ...
- C++ primer plus读书笔记——第12章 类和动态内存分配
第12章 类和动态内存分配 1. 静态数据成员在类声明中声明,在包含类方法的文件中初始化.初始化时使用作用域运算符来指出静态成员所属的类.但如果静态成员是整形或枚举型const,则可以在类声明中初始化 ...
- C++学习笔记(十一):void*指针、类型转换和动态内存分配
void*指针 void关键字表示“空类型”的概念.但是,这里的“空类型”不表示“任意类型”,而是表示不存在的意思,也就是说C/C++不允许你写语句void a,不存在类型为void的东西. void ...
- Java静态内存与动态内存分配的解析
1. 静态内存 静态内存是指在程序开始运行时由编译器分配的内存,它的分配是在程序开始编译时完成的,不占用CPU资源. 程序中的各种变量,在编译时系统已经为其分配了所需的内存空间,当该变量在作用域内使用 ...
- C++指针和动态内存分配
指针和动态内存分配 数组与指针 数组 数组名是一个指针常量. 数组名传递数据时,传递的是地址. 数组作为函数参数时不指定第一维大小. 对象数组 A a[2] = {A(1,2)}; 执行时先调用有参数 ...
随机推荐
- dubbo 相关面试题 有用
调用关系说明: · 0. 服务容器负责启动,加载,运行服务提供者. · 1. 服务提供者在启动时,向注册中心注册自己提供的服务. · 2. 服务消费者在启动时,向注册中心订阅自己所需的服务. · 3. ...
- convertTo
转自 http://blog.csdn.net/xiaxiazls/article/details/51204265 在使用Opencv中,常常会出现读取一个图片内容后要把图片内容的像素信息转为浮点并 ...
- 线程同步synchronized,wait,notifyAll 测试示例
https://www.cnblogs.com/LipeiNet/p/6475851.html 一 synchronized synchronized中文解释是同步,那么什么是同步呢,解释就是程序中 ...
- Hyper-V和vmware在虚拟机中安装xen总结
1. Hyper-V 在hyper-v中安装了ubuntu13.04,运行很好,使用起来的效果感觉比vmware要舒服.安装变异xen的内核也没有问题,可以正常的安装,update-grub之后也可以 ...
- LightOJ 1284 Lights inside 3D Grid (数学期望)
题意:在一个三维的空间,每个点都有一盏灯,开始全是关的.现在每次随机选两个点,把两个点之间的全部点,开关都按一遍,问k次过后开着的灯的期望数量: 析:很容易知道,如果一盏灯被按了奇数次,那么它肯定是开 ...
- SqueezeNet:AlexNet-level Accuracy with 50x fewer parameters and less than 0.5Mb model size
- Fire modules consisting of a 'squeeze' layer with 1*1 filters feeding an 'expand' layer with 1*1 a ...
- LibreOJ 6003 魔术球 (最大流)
题解:每次加入两个点,对于和为平方数的两个值所对应的点建边,反正网络流可以跑残量网络,所以就没有什么关系了…… 代码如下: #include<cmath> #include<queu ...
- CSS3的2D与3D转换
2D和3D转换涉及到数学中的知识,作为一个数学专业的毕业生,不研究一下岂不是对不起自己的专业? 首先来看几个参数: 1.transform-origin:origin(起源,起点),也即变形的起点,在 ...
- hibernate的获取session的两方法比较,和通过id获取对象的比较,一级缓存二级缓存
opensession与currentsession的联系与区别 在同一个线程中opensession的session是不一样的,而currentsession获取的session是一样的,这就保证了 ...
- WebApi与MVC Route 问题整理
1. 为WebAPI添加 Area后,完成了CustomControllerSelector的制定. 跟踪WebAPI底层,整理WebAPI源码后发现几个问题: 1. 使用Area的controlle ...