C++面向对象基础知识详解三

=======================================微笑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;
}

所以虚析够函数可以保证在任何情况下都不会出现由于析够函数未被调用而导致内存的泄漏。(内存泄漏:程序

失去对自己开辟内存空间的控制权)。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cugriver

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值