如果基类使用动态内存分配,并重新定义赋值和复制构造函数,这将怎样影响派生类的实现?这个问题的答案取决于派生类的属性。如果派生类也使用动态内存分配,那就需要注意学习新的小技巧。

派生类不适用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-继承和动态内存分配的更多相关文章

  1. C++之继承和动态内存分配

    C++之继承和动态内存分配         如果基类使用动态内存分配,并重新定义赋值和复制构造函数,这将如何影响派生类的实现呢?这取决于派生类的属性,如果派生类也使用动态内存分配,这将如何实现呢?这种 ...

  2. C++解析(25):关于动态内存分配、虚函数和继承中强制类型转换的疑问

    0.目录 1.动态内存分配 1.1 new和malloc的区别 1.2 delete和free的区别 2.虚函数 2.1 构造函数与析构函数是否可以成为虚函数? 2.2 构造函数与析构函数是否可以发生 ...

  3. C++_类和动态内存分配3-构造函数中使用new的注意事项

    如果在构造函数中使用new来初始化对象的指针成员时必须特别小心. 1 如果在构造函数中使用new来初始化指针成员,则应在析构函数中使用delete. 2 new和delete必须相互兼容.new对应于 ...

  4. String类型_static成员_动态内存分配_拷贝构造函数_const关键字_友元函数与友元类

    1:String类型 #include <iostream> using namespace std; int main() { //初始化方法 string s1 = "hel ...

  5. 《C++ Primer Plus》读书笔记之十—类和动态内存分配

    第12章 类和动态内存分配 1.不能在类声明中初始化静态成员变量,这是因为声明描述了如何分配内存,但并不分配内存.可以在类声明之外使用单独的语句进行初始化,这是因为静态类成员是单独存储的,而不是对象的 ...

  6. C++ primer plus读书笔记——第12章 类和动态内存分配

    第12章 类和动态内存分配 1. 静态数据成员在类声明中声明,在包含类方法的文件中初始化.初始化时使用作用域运算符来指出静态成员所属的类.但如果静态成员是整形或枚举型const,则可以在类声明中初始化 ...

  7. C++学习笔记(十一):void*指针、类型转换和动态内存分配

    void*指针 void关键字表示“空类型”的概念.但是,这里的“空类型”不表示“任意类型”,而是表示不存在的意思,也就是说C/C++不允许你写语句void a,不存在类型为void的东西. void ...

  8. Java静态内存与动态内存分配的解析

    1. 静态内存 静态内存是指在程序开始运行时由编译器分配的内存,它的分配是在程序开始编译时完成的,不占用CPU资源. 程序中的各种变量,在编译时系统已经为其分配了所需的内存空间,当该变量在作用域内使用 ...

  9. C++指针和动态内存分配

    指针和动态内存分配 数组与指针 数组 数组名是一个指针常量. 数组名传递数据时,传递的是地址. 数组作为函数参数时不指定第一维大小. 对象数组 A a[2] = {A(1,2)}; 执行时先调用有参数 ...

随机推荐

  1. 02-nginx信号量

    刚才完了nginx的编译,nginx的编译还是挺简单的.控制nginx:重启.关闭.只有孤零零的一个二进制文件nginx 通过信号来控制它,Linux操作系统进程与进程之间通过信号来通信.荷兰的一位计 ...

  2. 【codevs3990】中国余数定理2

    [题目描述]Skytree神犇最近在研究中国博大精深的数学.这时,Sci蒟蒻前来拜访,于是Skytree给Sci蒟蒻出了一道数学题:给定n个质数,以及k模这些质数的余数.问:在闭区间[a,b]中,有多 ...

  3. Select2 的使用

    实现这个下拉列表框 下载这两个官网上的CSS,JS 官网地址 https://select2.org/getting-started/installation 我自己存的高速下载地址 http://y ...

  4. linux上搭建图片服务器

    之前写过一个搭建图片服务器的随笔:https://www.cnblogs.com/xujingyang/p/7163290.html   ,现在回头看看,我去,感觉写的好乱,现在再整一个吧.o(╯□╰ ...

  5. hdu1269 Tarjan强连通分量 模板(转)

    #include<stdio.h> #include<iostream> #include<vector> using namespace std; ; vecto ...

  6. Struts2获取Action中的数据

    当我们用Struts2框架开发时,经常有要获取jsp页面的数据或者在jsp中获取后台传过来的数据(Action),那么怎么去获取自己想要的数据呢? 后台获取前端数据: 在java程序中生成要获取字段的 ...

  7. 在MYSQL中运用全文索引(FULLTEXT index)

    在MYSQL中使用全文索引(FULLTEXT index) MYSQL的一个很有用的特性是使用全文索引(FULLTEXT index)查找文本的能力.目前只有使用MyISAM类型表的时候有效(MyIS ...

  8. C++初始化,之不明白篇 cout<<x<<endl 与 cout<<"x = "<<cout<<x<<endl的输出的值会不一样

    代码如下 #include <iostream> using namespace std; class point { public :     int x;     int y;     ...

  9. nagios+influxdb+grafana的监控数据可视化流程

    nagios介绍 nagios是一款开源监控的应用,可用于监控本地和远程主机的日志.资源.死活等等诸多功能.通过snmp协议和nrpe协议. nagios的配置文件是由nconf上进行配置,然后点击生 ...

  10. IEnumerable、GetEnumerator、IEnumerator之间的关系。

    了解了这些也就明白了遍历的原理,晚安. using System; using System.Collections; public class Person { public Person(stri ...