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

派生类不适用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. Python学友

    独学而无友,则孤陋而寡闻,python学习过程中希望多和学友交流,一起进步. 开源中国 j_hao104 微信公众号: Pythoner每日一报 https://my.oschina.net/jhao ...

  2. 方向ajax(http long request实现实时通信)

    现在我们就要通过这种方法来实现实时通信,先说一下原理: 客户端发起一个ajax长链接查询,然后服务端就开始执行代码,主要是检查某个文件是否被更新,如果没有,睡一会(sleep),醒来接着检查 如果客户 ...

  3. Ubuntu 14.04 安装配置强大的星际译王(stardict)词典

    转载http://blog.csdn.net/huyisu/article/details/53437931

  4. URL 与 URI

    http://localhost:8080/TEST_Servlet/ClientRequest/test?name=wr getRequestURL:http://localhost:8080/TE ...

  5. 使用HttpServletRequestWrapper修改请求参数 和 使用HttpServletResponseWrapper截获响应数据

    Servlet规范中的Filter引入了一个功能强大的拦截模式.Filter能在request到达servlet的服务方法之前拦截request对象,而在服务方法转移控制后又能拦截response对象 ...

  6. Python基础入门-For循环

    For循环的功能比较强大,他可以帮助我们实现很多重复性的工作.而且for循环能迭代不同的数据结构.他的应用也十分的广泛,作为初学者,我们需要对循环的概念多加理解和练习.接下来我们就来学习for循环的一 ...

  7. MySQL性能调优与架构设计——第7章 MySQL数据库锁定机制

    第7章 MySQL数据库锁定机制 前言: 为了保证数据的一致完整性,任何一个数据库都存在锁定机制.锁定机制的优劣直接应想到一个数据库系统的并发处理能力和性能,所以锁定机制的实现也就成为了各种数据库的核 ...

  8. 如何让win32对话框居中显示

    在编写win32对话框程序,如果是用visual studio建的win32对话框程序,默认是不居中显示的,about 对话框也是这样的,用资源编辑器打开,可以在属性里面设置居中center 为tur ...

  9. sql server重建系统数据库

    方法一:https://bbs.csdn.net/topics/100013082 方法二:http://blog.51cto.com/jimshu/1095780 *** 方法三:https://b ...

  10. NSData 数据

    前言 NSData 和它的可变长子类 NSMutableData 是字节缓冲区的对象化封装.我们可以获得简单缓冲区,并进行一些转换操作. 通常我们并不会直接创建字节数据,而是从其他类型的内容转换成字节 ...