C++面向对象基础知识详解三
来源:互联网 发布:java异步日志系统 编辑:程序博客网 时间:2024/06/09 18:42
=======================================Begin===========================================
(7)带有静态成员变量的类对象内存存储分布
引言:类的静态成员变量属于类(即所有类对象共享该类的静态成员变量)。因此,对象的大小不包括静态成员变量所占的字节。
注意:类的静态成员变量必须在类外进行初始化,通过ClassName::staticmem的方式来访问。
(8)多重继承中“菱形”继承关系的内存分布
#include<iostream>#include<cstring>using namespace std;class Chinese{ public: typedef unsigned int uint32_t; private: uint32_t _cn_id; protected: uint32_t _cn_age; char* _cn_phone; public: char* _hobby; public: Chinese():_cn_id(0), _cn_age(0), _cn_phone(NULL), _hobby(NULL){} Chinese(uint32_t id, uint32_t age, char* strPhone, char* strHobby) :_cn_id(id), _cn_age(age){ uint32_t len = strlen(strPhone) + 1; this->_cn_phone = new char[len]; strcpy(this->_cn_phone, strPhone); len = strlen(strHobby)+1; this->_hobby = new char[len]; strcpy(this->_hobby, strHobby); } ~Chinese(){ delete[] this->_cn_phone; delete[] this->_hobby; } virtual void Display()const{ cout << "CID = " << _cn_age << endl; cout << "Phone = " << _cn_phone << endl; cout << "Hobby = " << _hobby << endl; }};class Singer : public Chinese{ private: char* _hobby; public: char* _songs; public: Singer():Chinese(),_hobby(NULL), _songs(NULL){}; Singer(uint32_t id, uint32_t age, char* phone, char* hobby, char* songs) :Chinese(id, age, phone, hobby){ uint32_t len = strlen(hobby)+1; _hobby = new char[len]; strcpy(this->_hobby, hobby); len = strlen(songs)+1; _songs = new char[len]; strcpy(this->_songs, songs); } ~Singer(){ delete[] this->_hobby; delete[] this->_songs; } virtual void Display()const{ cout << "Age = " << _cn_age << endl; cout << "Phone = " << _cn_phone << endl; cout << "Hobby = " << _hobby << endl; cout << "Songs = " << _songs << endl; } };class Writer : public Chinese { private: char* _hobby; public: char* _books; public: Writer():Chinese(),_hobby(NULL),_books(NULL){}; Writer(uint32_t id, uint32_t age, char* phone, char* hobby, char* books) :Chinese(id, age, phone, hobby){ uint32_t len = strlen(hobby)+1; _hobby = new char[len]; strcpy(_hobby, hobby); len = strlen(books)+1; _books = new char[len]; strcpy(_books, books); } ~Writer(){ delete[] _hobby; delete[] _books; } virtual void Display()const{ cout << "Age = " << _cn_age << endl; cout << "Phone = " << _cn_phone << endl; cout << "Hobby = " << _hobby << endl; cout << "Books = " << _books << endl; } };class SingerWriter: public Singer, public Writer{ public: SingerWriter():Singer(),Writer(){}; SingerWriter(uint32_t id, uint32_t age, char* phone, char* hobby, char* songs, char* books) :Singer(id,age,phone, hobby, songs), Writer(id, age, phone, hobby, books){ } ~SingerWriter(){ } virtual void Display() const{ Singer::Display(); }};int main(void){ SingerWriter sw(100, 22, (char*)"1x0xxxxyyyy", (char*)"Swimming and Running", (char*)"<<Fade>> and <<What are words>>", (char*)"<<OS>> and <<Newwork>>"); SingerWriter* psw = &sw; psw->Display(); return 0;}
分析:可以直观的看到子类SingerWriter对象保留了基类Chinese类同名数据成员的多份拷贝,例如_hobby成员变量。
注意2点:(1)基类中的同名数据成员在派生类中被“屏蔽",成为”不可见"的。(2)有多重继承引起的函数调用二义性,可以
通过通过ClassName::functionName显示调用。关键的问题:Singer类对Chinese类中的_cn_id赋值100,Writer类对
Chinese中_cn_id赋值200, 若SingerWriter类对象访问Chinese中的_cn_id时,那么_cn_id是100还是200??
其问题的本质是为什么SingerWriter类对象需要保留Chinese中的数据成员的2份拷贝?如果让SingerWriter类对象之保留
Chinese中数据成员的1分拷贝,问题也就解决了。为此C++引入了一种新的技术——虚基类。
(9)虚基类环境下“菱形”继承关系的内存分布
虚基类使得多个类(有相同的基类)派生出的类对象只继承一个基类对象。在声明类继承声明中使用virtual关键字
class Singer : virtual public Chinese{}
class Writer : virtual public Chinese{}
同时,使用新的构造函数规则: SingerWriter():Chinese(),Singer(),Writer(){}
(10)抽象类和纯虚函数
抽象类的唯一目的就是用它作为基类去建立派生类。抽象类中至少含有一个纯虚函数。换句话说,含有纯需函数的类一定是抽象
类。虚函数的明显标志就是虚函数=0。纯虚函数的作用是预留函数名,让派生类具体实现该函数。因此抽象类不能实例化,即抽
象类没有对象。
(11)虚析构函数
析够函数的作用在对象撤销前做“清理工作"(堆的释放,内存空间地址的释放)。派生类的析构过程是先调用本类自己的析够函数,
再调用基类的析够函数。但是如果基类的指针变量new开辟了一块内存空间,当基类指针指向派生类对象时,且delete基类指针,
发生一个情况: 系统只执行基类析够函数,不执行派生类的析够函数。
#include<iostream>using namespace std;class Point{ public: Point(){}; ~Point(){cout << "Point::~Point()"<<endl;}};class Circle : public Point{ public: Circle():Point(){}; ~Circle(){cout << "Circle::~Circle()"<<endl;}};int main(void){ Point* p = new Circle(); delete p; return 0;}
所以虚析够函数可以保证在任何情况下都不会出现由于析够函数未被调用而导致内存的泄漏。(内存泄漏:程序
失去对自己开辟内存空间的控制权)。
- C++面向对象基础知识详解三
- C++基础知识(三) 面向对象
- 黑马程序员,Java基础知识三:面向对象
- java面向对象基础知识(三)
- C++面向对象基础知识详解一
- C++面向对象基础知识详解二
- Objective-C面向对象编程基础知识
- 详解面向对象的三大特性
- 面向对象三大特征(详解)
- 黑马程序员 Java基础知识总结-面向对象三大特征
- 黑马程序员---java基础知识(三):面向对象
- 【java基础知识】面向对象的三大特性之封装
- 【java基础知识】面向对象三大特性之继承
- 【Java基础知识】面向对象三大特性之多态
- Object-c 面向对象(三)
- 【C#】-面向对象三大特征
- 基础知识----面向对象思想
- 面向对象----类基础知识
- Cocos2d-Lua之面向对象的继承
- Android之DialogFragment
- 在OpenWrt上安装DNSCrypt
- [hdu1596] find the safest road
- sql server 连接不上的几种解决
- C++面向对象基础知识详解三
- 使用strapdown.js解析markdown
- Skia深入分析7——区域解码
- 多种方法给页面设置标题,最容易忽略清单配置文件
- 云计算的三种服务模式:IaaS,PaaS和SaaS
- mybatis连接mysql数据库插入中文乱码
- Namenode服务停止Error: flush failed for required journal (JournalAndStream(mgr=QJM to
- 在Mysql中如何显示所有用户?
- 设计模式:单例模式及其线程安全