日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

c++面向对象三大特征封装、继承和多态知识总结

發(fā)布時(shí)間:2024/4/18 c/c++ 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++面向对象三大特征封装、继承和多态知识总结 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

面向?qū)ο笕筇卣?#xff1a;封裝,繼承,多態(tài);

一、封裝:該公開(kāi)的就公開(kāi)話,該私有的就隱藏掉,主要是由publicprivate實(shí)現(xiàn);作用是便于分工和分模塊,防止不必要的擴(kuò)展;

二、繼承:就是一種傳承,可以把父類(lèi)型中的數(shù)據(jù)傳承到子類(lèi)中,子類(lèi)除了傳承了父類(lèi)的數(shù)據(jù)之外,還可以對(duì)父類(lèi)型進(jìn)行擴(kuò)展;

公開(kāi)繼承? public

保護(hù)繼承? protected

私有繼承? private

保護(hù)成員:在子類(lèi)和本類(lèi)中可以訪問(wèn),其他不行;


1、公開(kāi)繼承:在公開(kāi)繼承下,父類(lèi)型中的數(shù)據(jù)是公開(kāi)的到子類(lèi)型中權(quán)限是公開(kāi)的;父類(lèi)型中保護(hù)權(quán)限的數(shù)據(jù)到子類(lèi)中是保護(hù)的;父類(lèi)中私有的數(shù)據(jù)到子類(lèi)中會(huì)隱藏掉(就是說(shuō)看不見(jiàn)權(quán)限,但是實(shí)際上式在子類(lèi)中的);

2、私有繼承:在私有繼承下,父類(lèi)中的公開(kāi)數(shù)據(jù)到子類(lèi)中變成私有的,父類(lèi)中的保護(hù)數(shù)據(jù)到子類(lèi)中稱(chēng)為私有的,父類(lèi)中的私有數(shù)據(jù)到子類(lèi)中隱藏;

3、保護(hù)繼承:保護(hù)繼承下,父類(lèi)中的公開(kāi)數(shù)據(jù)和保護(hù)數(shù)據(jù)到了子類(lèi)中都成為保護(hù)權(quán)限,父類(lèi)中私有的數(shù)據(jù)到了子類(lèi)中就變成了隱藏的;


4、注意:不管何種類(lèi)型的繼承關(guān)系,父類(lèi)私有成員到子類(lèi)中都成為了隱藏掉。

公開(kāi)繼承下的public成員和protected成員的權(quán)限變化:

[cpp] view plain copy print?
  • #include?<iostream>??
  • using?namespace?std;??
  • ??
  • class?A{??
  • public:??
  • ????int?a;??
  • ????int?geta(){??
  • ????????a?=?300;??
  • ????????return?a;??
  • ????}??
  • ????/*保護(hù)類(lèi)型成員在本類(lèi)和子類(lèi)中可以訪問(wèn)*/??
  • protected:??
  • ????int?b;??
  • private:??
  • ????int?c;??
  • };??
  • ??
  • class?B:public?A{??
  • ????//int?x;??
  • public:??
  • ????void?getb(){??
  • ????????b?=?200;??
  • ????}??
  • ????void?show(){??
  • ????????cout?<<?b?<<?endl;??
  • ????}??
  • ????void?showa(){??
  • ????????cout<<?a<<endl;??
  • ????}??
  • };???
  • /*關(guān)鍵在于如何設(shè)置接口,成功合理的訪問(wèn)到各種類(lèi)型的數(shù)據(jù)*/??
  • int?main(){??
  • ????B?pex;??
  • ????/*公開(kāi)繼承public成員依舊是public,所以可以類(lèi)外訪問(wèn)*/??
  • ????pex.a?=?100;??
  • ????/*b是保護(hù)類(lèi)型成員,可以通過(guò)設(shè)置public接口來(lái)訪問(wèn)*/??
  • ????pex.getb();??
  • ????pex.show();??
  • ????/*隱藏成員的問(wèn)題,怎么訪問(wèn)到隱藏的成員*/??
  • ????pex.geta();??
  • ????pex.showa();??
  • ????//A?a?=?pex;//子類(lèi)類(lèi)型賦給了父類(lèi)類(lèi)型??
  • ????//a.geta();??
  • ????//cout?<<?a.a?<<?endl;??
  • }??
  • #include <iostream> using namespace std;class A{ public:int a;int geta(){a = 300;return a;}/*保護(hù)類(lèi)型成員在本類(lèi)和子類(lèi)中可以訪問(wèn)*/ protected:int b; private:int c; };class B:public A{//int x; public:void getb(){b = 200;}void show(){cout << b << endl;}void showa(){cout<< a<<endl;} }; /*關(guān)鍵在于如何設(shè)置接口,成功合理的訪問(wèn)到各種類(lèi)型的數(shù)據(jù)*/ int main(){B pex;/*公開(kāi)繼承public成員依舊是public,所以可以類(lèi)外訪問(wèn)*/pex.a = 100;/*b是保護(hù)類(lèi)型成員,可以通過(guò)設(shè)置public接口來(lái)訪問(wèn)*/pex.getb();pex.show();/*隱藏成員的問(wèn)題,怎么訪問(wèn)到隱藏的成員*/pex.geta();pex.showa();//A a = pex;//子類(lèi)類(lèi)型賦給了父類(lèi)類(lèi)型//a.geta();//cout << a.a << endl; }


    5、私有繼承下的成員的權(quán)限變化關(guān)系,注意如何設(shè)置合理的 訪問(wèn)接口去訪問(wèn) 隱藏的數(shù)據(jù)成員。

    [cpp] view plain copy print?
  • /*私有繼承下的權(quán)限變化,關(guān)鍵是設(shè)置合理的接口訪問(wèn)?
  • 父類(lèi)中的各種類(lèi)型的數(shù)據(jù)成員*/??
  • #include?<iostream>??
  • using?namespace?std;??
  • ??
  • class?A{??
  • private:??
  • ????void?showa(){??
  • ????????cout?<<?"this?is?showa()"?<<?endl;??
  • ????}??
  • protected:??
  • ????void?showb(){??
  • ????????cout?<<?"this?is?showb"?<<?endl;??
  • ????}??
  • public:??
  • ????void?showc(){??
  • ????????cout?<<?"this?is?showc"?<<?endl;??
  • ????}??
  • ????void?geta(){//設(shè)置合理的接口訪問(wèn)A中的私有數(shù)據(jù)??
  • ????????showa();??
  • ????}??
  • };??
  • ??
  • class?B:private?A{??
  • public:??
  • ????void?show(){??
  • ????????showc();??
  • ????????showb();??
  • ????????geta();??
  • ????}??
  • };??
  • ??
  • int?main(){??
  • ????B?b;??
  • ????//A?a?=?b;對(duì)比公開(kāi)繼承,對(duì)比一下??
  • ????b.show();??
  • }??
  • /*私有繼承下的權(quán)限變化,關(guān)鍵是設(shè)置合理的接口訪問(wèn) 父類(lèi)中的各種類(lèi)型的數(shù)據(jù)成員*/ #include <iostream> using namespace std;class A{ private:void showa(){cout << "this is showa()" << endl;} protected:void showb(){cout << "this is showb" << endl;} public:void showc(){cout << "this is showc" << endl;}void geta(){//設(shè)置合理的接口訪問(wèn)A中的私有數(shù)據(jù)showa();} };class B:private A{ public:void show(){showc();showb();geta();} };int main(){B b;//A a = b;對(duì)比公開(kāi)繼承,對(duì)比一下b.show(); }


    6、突破成員訪問(wèn)權(quán)限,可以設(shè)置合理的訪問(wèn)接口,也可以使用友元類(lèi)。

    [cpp] view plain copy print?
  • /*友元類(lèi)*/??
  • #include?<iostream>??
  • using?namespace?std;??
  • ??
  • class?A{??
  • private:??
  • ????int?x;??
  • ????int?y;??
  • public:??
  • ????A():x(10),y(123){}??
  • ????/*B,C聲明為A的友元類(lèi)之后,可以訪問(wèn)到父類(lèi)的所有類(lèi)型成員*/??
  • ????friend?class?B;??
  • ????friend?class?C;??
  • };??
  • ??
  • class?B:public?A{??
  • public:??
  • ????void?show(){??
  • ????????cout?<<?x?<<?"---"?<<?y?<<?endl;???
  • ????}??
  • };??
  • ??
  • class?C{??
  • public:??
  • ????void?show(){??
  • ????????A?a;??
  • ????????cout?<<a.x<<?"---"?<<?a.y?<<?endl;??
  • ????}??
  • };??
  • ??
  • int?main(){??
  • ????B?b;??
  • ????b.show();??
  • ????C?c;??
  • ????c.show();??
  • }??
  • /*友元類(lèi)*/ #include <iostream> using namespace std;class A{ private:int x;int y; public:A():x(10),y(123){}/*B,C聲明為A的友元類(lèi)之后,可以訪問(wèn)到父類(lèi)的所有類(lèi)型成員*/friend class B;friend class C; };class B:public A{ public:void show(){cout << x << "---" << y << endl; } };class C{ public:void show(){A a;cout <<a.x<< "---" << a.y << endl;} };int main(){B b;b.show();C c;c.show(); }


    7、繼承中構(gòu)造函數(shù)、析構(gòu)函數(shù)、賦值運(yùn)算符函數(shù)和拷貝構(gòu)造函數(shù)

    構(gòu)造函數(shù)和析構(gòu)函數(shù)是不能被繼承的,但是可以被調(diào)用。并且子類(lèi)一定會(huì)調(diào)用父類(lèi)的構(gòu)造函數(shù);

    子類(lèi)默認(rèn)調(diào)用父類(lèi)的無(wú)參構(gòu)造,也可以制定調(diào)用構(gòu)造函數(shù);

    析構(gòu)函數(shù)的調(diào)用和構(gòu)造函數(shù)的調(diào)用順序相反;

    拷貝構(gòu)造函數(shù)和賦值運(yùn)算符函數(shù)也不能被繼承:在子類(lèi)不提供拷貝構(gòu)造和賦值運(yùn)算符時(shí),子類(lèi)默認(rèn)調(diào)用父類(lèi)的賦值運(yùn)算符和拷貝構(gòu)造函數(shù)。但子類(lèi)一旦提供拷貝構(gòu)造和賦值運(yùn)算符函數(shù)則不再調(diào)用父類(lèi)拷貝構(gòu)造和賦值運(yùn)算符函數(shù)。

    [cpp] view plain copy print?
  • /*繼承中構(gòu)造函數(shù)和析構(gòu)函數(shù)的調(diào)用:構(gòu)造函數(shù)和析構(gòu)函數(shù)不可以?
  • 被繼承,但是可以被調(diào)用,而且子類(lèi)肯定會(huì)調(diào)用父類(lèi)的構(gòu)造函數(shù)?
  • 和析構(gòu)函數(shù)。這種機(jī)制可以很自然的用于訪問(wèn)父類(lèi)的私有成員*/??
  • #include?<iostream>??
  • using?namespace?std;??
  • ??
  • class?A{??
  • private:??
  • ????int?x;??
  • public:??
  • ????//A(){cout?<<?"A()"?<<?endl;}??
  • ????A(int?x?=?0):x(x){??
  • ????????cout?<<"A()構(gòu)造"<<endl;??
  • ????????cout?<<?x?<<?endl;}??
  • ????~A(){cout?<<?"~A()"?<<?endl;}??
  • ????int?_get(){??
  • ????????return?x;??
  • ????}??
  • };??
  • ??
  • class?B:public?A{??
  • public:??
  • ????/*在初始化參數(shù)列表中可以指定調(diào)用父類(lèi)的構(gòu)造函數(shù),指定調(diào)用構(gòu)造函數(shù)并且給?
  • ????父類(lèi)中的私有成員賦值*/??
  • ????/*注意:子類(lèi)默認(rèn)調(diào)用父類(lèi)的無(wú)參構(gòu)造,如果下面的代碼沒(méi)有:A(100),則會(huì)調(diào)用無(wú)參構(gòu)造,但是父類(lèi)無(wú)參構(gòu)造?
  • ????被注釋掉,所以會(huì)出錯(cuò)*/??
  • ????B():A(100){??
  • ????????//x?=?200;??
  • ????????//A(100);??
  • ????????cout?<<?"B()"?<<?endl;??
  • ????}??
  • ????//訪問(wèn)有參構(gòu)造的方式,理解這種方式的作用??
  • ????/*注意,這種機(jī)制下的構(gòu)造函數(shù)所賦的值是賦到了子類(lèi)中的數(shù)據(jù)x中,?
  • ????而父類(lèi)中的x仍然為0*/??
  • ????~B(){cout?<<?"~B()"?<<?endl;}??
  • ????int?getbx(){??
  • ????????return?_get();??
  • ????}??
  • };??
  • int?main(){??
  • ????A?a;//構(gòu)建A對(duì)象,此時(shí)A類(lèi)構(gòu)造被調(diào)用,并打印出了值??
  • ??
  • ????B?b;//B類(lèi)為無(wú)參構(gòu)造,首先調(diào)用了A的構(gòu)造,在調(diào)用B的構(gòu)造??
  • ??
  • ????//打印a對(duì)象中的x成員??
  • ????cout?<<a._get()<<endl;//a對(duì)象中的x為0??
  • ??
  • ????//打印b對(duì)象中的x??
  • ????cout?<<?b.getbx()<<endl;//是100??
  • ????/*一層一層的退,先調(diào)用b的析構(gòu),在調(diào)用a的析構(gòu)*/??
  • }??
  • /*繼承中構(gòu)造函數(shù)和析構(gòu)函數(shù)的調(diào)用:構(gòu)造函數(shù)和析構(gòu)函數(shù)不可以 被繼承,但是可以被調(diào)用,而且子類(lèi)肯定會(huì)調(diào)用父類(lèi)的構(gòu)造函數(shù) 和析構(gòu)函數(shù)。這種機(jī)制可以很自然的用于訪問(wèn)父類(lèi)的私有成員*/ #include <iostream> using namespace std;class A{ private:int x; public://A(){cout << "A()" << endl;}A(int x = 0):x(x){cout <<"A()構(gòu)造"<<endl;cout << x << endl;}~A(){cout << "~A()" << endl;}int _get(){return x;} };class B:public A{ public:/*在初始化參數(shù)列表中可以指定調(diào)用父類(lèi)的構(gòu)造函數(shù),指定調(diào)用構(gòu)造函數(shù)并且給父類(lèi)中的私有成員賦值*//*注意:子類(lèi)默認(rèn)調(diào)用父類(lèi)的無(wú)參構(gòu)造,如果下面的代碼沒(méi)有:A(100),則會(huì)調(diào)用無(wú)參構(gòu)造,但是父類(lèi)無(wú)參構(gòu)造被注釋掉,所以會(huì)出錯(cuò)*/B():A(100){//x = 200;//A(100);cout << "B()" << endl;}//訪問(wèn)有參構(gòu)造的方式,理解這種方式的作用/*注意,這種機(jī)制下的構(gòu)造函數(shù)所賦的值是賦到了子類(lèi)中的數(shù)據(jù)x中,而父類(lèi)中的x仍然為0*/~B(){cout << "~B()" << endl;}int getbx(){return _get();} }; int main(){A a;//構(gòu)建A對(duì)象,此時(shí)A類(lèi)構(gòu)造被調(diào)用,并打印出了值B b;//B類(lèi)為無(wú)參構(gòu)造,首先調(diào)用了A的構(gòu)造,在調(diào)用B的構(gòu)造//打印a對(duì)象中的x成員cout <<a._get()<<endl;//a對(duì)象中的x為0//打印b對(duì)象中的xcout << b.getbx()<<endl;//是100/*一層一層的退,先調(diào)用b的析構(gòu),在調(diào)用a的析構(gòu)*/ }

    拷貝構(gòu)造和賦值運(yùn)算符的問(wèn)題

    [cpp] view plain copy print?
  • #include?<iostream>??
  • using?namespace?std;??
  • /*系統(tǒng)一旦提供構(gòu)造函數(shù),系統(tǒng)默認(rèn)的構(gòu)造函數(shù)將被回收?
  • 記住,拷貝構(gòu)造也是構(gòu)造函數(shù)*/??
  • class?A{??
  • ????int?arr;??
  • public:??
  • ????A(){}??
  • ????//A(int?x?=?0):arr(x){}??
  • ????A(const?A&?a){??
  • ????????cout?<<?"父類(lèi)拷貝構(gòu)造"?<<?endl;??
  • ????}??
  • ????void?operator=(const?A&?a){??
  • ????????cout?<<?"父類(lèi)賦值運(yùn)算符函數(shù)"?<<?endl;??
  • ????}??
  • };??
  • /*有指針類(lèi)型的成員時(shí),采用默認(rèn)機(jī)制就麻煩了*/??
  • class?B:public?A{??
  • ????//int?*?pi;??
  • public:??
  • ????B(){}??
  • ????B(const?B&?b):A(b){????????????????????????
  • ????????//子類(lèi)中提供了拷貝構(gòu)造函數(shù)將不再調(diào)用父類(lèi)的拷貝構(gòu)造??
  • ????????cout?<<?"子類(lèi)拷貝構(gòu)造"?<<?endl;??
  • ????}??
  • ????void?operator=(const?B&?b){??
  • ????????A::operator=(b);?????????//調(diào)用父類(lèi)的拷貝構(gòu)造函數(shù)的機(jī)制??
  • ????????cout?<<?"子類(lèi)賦值運(yùn)算符函數(shù)"<<?endl;??
  • ????}??
  • };??
  • ??
  • int?main(){??
  • ????B?a;??
  • ????B?b?=?a;??
  • ????B?c;??
  • ????c?=?a;??
  • }??
  • #include <iostream> using namespace std; /*系統(tǒng)一旦提供構(gòu)造函數(shù),系統(tǒng)默認(rèn)的構(gòu)造函數(shù)將被回收 記住,拷貝構(gòu)造也是構(gòu)造函數(shù)*/ class A{int arr; public:A(){}//A(int x = 0):arr(x){}A(const A& a){cout << "父類(lèi)拷貝構(gòu)造" << endl;}void operator=(const A& a){cout << "父類(lèi)賦值運(yùn)算符函數(shù)" << endl;} }; /*有指針類(lèi)型的成員時(shí),采用默認(rèn)機(jī)制就麻煩了*/ class B:public A{//int * pi; public:B(){}B(const B& b):A(b){ //子類(lèi)中提供了拷貝構(gòu)造函數(shù)將不再調(diào)用父類(lèi)的拷貝構(gòu)造cout << "子類(lèi)拷貝構(gòu)造" << endl;}void operator=(const B& b){A::operator=(b); //調(diào)用父類(lèi)的拷貝構(gòu)造函數(shù)的機(jī)制cout << "子類(lèi)賦值運(yùn)算符函數(shù)"<< endl;} };int main(){B a;B b = a;B c;c = a; }


    8,名字隱藏

    名字隱藏機(jī)制:子類(lèi)中如果定義了和父類(lèi)中同名的數(shù)據(jù),這些數(shù)據(jù)包括成員變量和成員函數(shù)。則會(huì)把父類(lèi)中的數(shù)據(jù)隱藏掉。

    注意:只要名字相同,計(jì)算返回值或者形參列表不同,也會(huì)被隱藏。隱藏不代表就沒(méi)有了,可以通過(guò)類(lèi)名作用域::訪問(wèn)到被隱藏的成員。

    [cpp] view plain copy print?
  • #include?<iostream>??
  • using?namespace?std;??
  • ??
  • class?A{??
  • public:??
  • ????int?x;??
  • ????int?show(){??
  • ????????cout?<<?"show?A"?<<?endl;??
  • ????????return?0;??
  • ????}??
  • ????A(){x=20;}??
  • ????A(int?x):x(x){cout?<<?"show?A(int?x)"?<<?endl;}??
  • ????void?shouu(){??
  • ????????cout?<<"shouu()"<<endl;??
  • ????}??
  • };??
  • ??
  • class?B:public?A{??
  • public:??
  • ????int?x;??
  • ????int?y;??
  • ????B(){cout?<<?"B()"?<<?endl;}??
  • ????void?show(){??
  • ????????cout?<<?"show?B"?<<?endl;??
  • ????????//A::show();??
  • ????}??
  • };??
  • ??
  • int?main(){??
  • ????B?b;??
  • ????b.shouu();??
  • ????//cout?<<?b.x?<<?endl;??
  • ????//cout?<<?b.A::x?<<?endl;???//突破名字隱藏機(jī)制??
  • ????//int?c?=?b.show();被隱藏,無(wú)法訪問(wèn)??
  • ????//b.A::show();??
  • }??
  • #include <iostream> using namespace std;class A{ public:int x;int show(){cout << "show A" << endl;return 0;}A(){x=20;}A(int x):x(x){cout << "show A(int x)" << endl;}void shouu(){cout <<"shouu()"<<endl;} };class B:public A{ public:int x;int y;B(){cout << "B()" << endl;}void show(){cout << "show B" << endl;//A::show();} };int main(){B b;b.shouu();//cout << b.x << endl;//cout << b.A::x << endl; //突破名字隱藏機(jī)制//int c = b.show();被隱藏,無(wú)法訪問(wèn)//b.A::show(); }


    9、多繼承和函數(shù)重寫(xiě)

    多繼承是c++特有的語(yǔ)法機(jī)制,表現(xiàn)為一個(gè)子類(lèi)有多個(gè)直接的父類(lèi)。

    [cpp] view plain copy print?
  • #include?<iostream>??
  • using?namespace?std;??
  • ??
  • class?phone{??
  • ????double?price;??
  • public:??
  • ????//phone();??
  • ????phone(double?price?=?15):price(price){cout?<<?"phone"?<<?endl;}??
  • ????~phone(){cout?<<?"~phone"?<<?endl;}??
  • ????void?call(){??
  • ????????cout?<<?"use?calling"?<<?endl;??
  • ????}??
  • ????double?getprice(){??
  • ????????return?price;??
  • ????}??
  • };??
  • ??
  • class?MP3{??
  • ????double?price;??
  • public:??
  • ????MP3(double?price?=?20):price(price){cout?<<?"MP3"?<<?endl;}??
  • ????~MP3(){cout?<<?"~MP3"?<<?endl;}??
  • ????void?play(){??
  • ????????cout?<<?"use?to?listening?music"?<<?endl;??
  • ????}??
  • ????double?getprice(){??
  • ????????return?price;??
  • ????}??
  • };???
  • ??
  • class?vedio{??
  • ????double?price;??
  • public:??
  • ????vedio(double?price?=?0):price(price){cout?<<?"vedio"?<<?endl;}??
  • ????~vedio(){cout?<<?"~vedio"?<<?endl;}??
  • ????void?vcd(){??
  • ????????cout?<<?"watch?vedio"?<<?endl;??
  • ????}???
  • ????double?getprice(){??
  • ????????return?price;??
  • ????}??
  • };??
  • /*多繼承*/??
  • class?iphone:public?phone,public?MP3,public?vedio{??
  • public:??
  • ????double?getprice(){??
  • ????????return?phone::getprice()?+?MP3::getprice()?+?vedio::getprice();??
  • ????}??
  • };??
  • ??
  • int?main(){??
  • ????iphone?iphone6;??
  • ????//cout?<<?sizeof(iphone)?<<?endl;??
  • ????cout?<<?iphone6.MP3::getprice()?<<?endl;??
  • ????cout?<<?iphone6.phone::getprice()?<<?endl;??
  • ????cout?<<?iphone6.getprice()?<<?endl;????//用名字隱藏機(jī)制解決多分?jǐn)?shù)據(jù)同名沖突的問(wèn)題??
  • }??
  • #include <iostream> using namespace std;class phone{double price; public://phone();phone(double price = 15):price(price){cout << "phone" << endl;}~phone(){cout << "~phone" << endl;}void call(){cout << "use calling" << endl;}double getprice(){return price;} };class MP3{double price; public:MP3(double price = 20):price(price){cout << "MP3" << endl;}~MP3(){cout << "~MP3" << endl;}void play(){cout << "use to listening music" << endl;}double getprice(){return price;} }; class vedio{double price; public:vedio(double price = 0):price(price){cout << "vedio" << endl;}~vedio(){cout << "~vedio" << endl;}void vcd(){cout << "watch vedio" << endl;} double getprice(){return price;} }; /*多繼承*/ class iphone:public phone,public MP3,public vedio{ public:double getprice(){return phone::getprice() + MP3::getprice() + vedio::getprice();} };int main(){iphone iphone6;//cout << sizeof(iphone) << endl;cout << iphone6.MP3::getprice() << endl;cout << iphone6.phone::getprice() << endl;cout << iphone6.getprice() << endl; //用名字隱藏機(jī)制解決多分?jǐn)?shù)據(jù)同名沖突的問(wèn)題 }


    多繼承遇到的問(wèn)題:上面的代碼用sizeof就可以看到,子類(lèi)在多繼承的時(shí)候會(huì)多次復(fù)制頂層數(shù)據(jù),而我們期望的是price這個(gè)成員只需要復(fù)制一份就可以了,因?yàn)槎嘤嗟膹?fù)制是無(wú)意義的。首先采用頂層抽象的方式,將三個(gè)父類(lèi)抽象到更高的層面上。

    [cpp] view plain copy print?
  • #include?<iostream>??
  • using?namespace?std;??
  • /*抽象到更高層的類(lèi)中*/??
  • class?product{??
  • ????double?price;??
  • public:??
  • ????double?getprice(){??
  • ????????return?price;??
  • ????}??
  • ????product(double?price?=?0):price(price){cout?<<"product"<<endl;}??
  • };??
  • class?phone:public?product{??
  • public:??
  • ????//phone();??
  • ????phone(double?price?=?15):product(price){cout?<<?"phone"?<<?endl;}??
  • ????~phone(){cout?<<?"~phone"?<<?endl;}??
  • ????void?call(){??
  • ????????cout?<<?"use?calling"?<<?endl;??
  • ????}??
  • };??
  • ??
  • class?MP3:public?product{??
  • public:??
  • ????MP3(double?price?=?20):product(price){cout?<<?"MP3"?<<?endl;}??
  • ????~MP3(){cout?<<?"~MP3"?<<?endl;}??
  • ????void?play(){??
  • ????????cout?<<?"use?to?listening?music"?<<?endl;??
  • ????}??
  • };???
  • ??
  • class?vedio:public?product{??
  • public:??
  • ????vedio(double?price?=?0):product(price){cout?<<?"vedio"?<<?endl;}??
  • ????~vedio(){cout?<<?"~vedio"?<<?endl;}??
  • ????void?vcd(){??
  • ????????cout?<<?"watch?vedio"?<<?endl;??
  • ????}???
  • };??
  • class?iphone:public?phone,public?MP3,public?vedio{??
  • ??????
  • };??
  • ??
  • int?main(){??
  • ????iphone?iphone6;??
  • ????//cout?<<?iphone6.getprice()?<<?endl;同樣會(huì)產(chǎn)生沖突的問(wèn)題??
  • ????//cout?<<?sizeof(iphone)?<<?endl;??
  • ????cout?<<?iphone6.MP3::getprice()?<<?endl;??
  • ????cout?<<?iphone6.phone::getprice()?<<?endl;??
  • ????//cout?<<?iphone6.getprice()?<<?endl;//直接調(diào)用產(chǎn)生沖突問(wèn)題,編譯器不知道該調(diào)用哪一個(gè)??
  • }??
  • #include <iostream> using namespace std; /*抽象到更高層的類(lèi)中*/ class product{double price; public:double getprice(){return price;}product(double price = 0):price(price){cout <<"product"<<endl;} }; class phone:public product{ public://phone();phone(double price = 15):product(price){cout << "phone" << endl;}~phone(){cout << "~phone" << endl;}void call(){cout << "use calling" << endl;} };class MP3:public product{ public:MP3(double price = 20):product(price){cout << "MP3" << endl;}~MP3(){cout << "~MP3" << endl;}void play(){cout << "use to listening music" << endl;} }; class vedio:public product{ public:vedio(double price = 0):product(price){cout << "vedio" << endl;}~vedio(){cout << "~vedio" << endl;}void vcd(){cout << "watch vedio" << endl;} }; class iphone:public phone,public MP3,public vedio{};int main(){iphone iphone6;//cout << iphone6.getprice() << endl;同樣會(huì)產(chǎn)生沖突的問(wèn)題//cout << sizeof(iphone) << endl;cout << iphone6.MP3::getprice() << endl;cout << iphone6.phone::getprice() << endl;//cout << iphone6.getprice() << endl;//直接調(diào)用產(chǎn)生沖突問(wèn)題,編譯器不知道該調(diào)用哪一個(gè) }

    上面的代碼中,product的構(gòu)造函數(shù) 被調(diào)用了三次,因?yàn)檫@種繼承是一級(jí)一級(jí)的來(lái)的,構(gòu)造子類(lèi)的時(shí)候找父類(lèi),發(fā)現(xiàn)父類(lèi)還有父類(lèi),就去調(diào)用爺爺類(lèi)的構(gòu)造函數(shù),三次繼承,三次調(diào)用。


    這種繼承方式構(gòu)成了一種菱形或者鉆石型的繼承,叫做菱形繼承或者鉆石繼承,但鉆石繼承并沒(méi)有實(shí)際解決數(shù)據(jù)多次復(fù)制的問(wèn)題,為了解決菱形繼承,c++提出了虛繼承。虛繼承就是在繼承的時(shí)候加上virtual關(guān)鍵字修飾即可。虛繼承對(duì)于共同的成員父親類(lèi)從爺爺類(lèi)那里繼承來(lái)的,這里為double price,子類(lèi)直接越級(jí)訪問(wèn),直接從爺爺類(lèi)那里繼承price。

    [cpp] view plain copy print?
  • /*類(lèi)中也會(huì)有對(duì)齊和補(bǔ)齊*/??
  • #include?<iostream>??
  • using?namespace?std;??
  • /*抽象到更高層的類(lèi)中*/??
  • class?product{??
  • ????int?price;??
  • public:??
  • ????int??getprice(){??
  • ????????return?price;??
  • ????}??
  • ????product(double?price?=?0):price(price){cout?<<?"product"?<<?endl;}??
  • };??
  • ??
  • class?phone:virtual?public?product{??
  • public:??
  • ????//phone();??
  • ????phone(double?price?=?15):product(price){cout?<<?"phone"?<<?endl;}??
  • ????~phone(){cout?<<?"~phone"?<<?endl;}??
  • ????void?call(){??
  • ????????cout?<<?"use?calling"?<<?endl;??
  • ????}??
  • };??
  • ??
  • class?MP3:virtual?public?product{??
  • public:??
  • ????MP3(double?price?=?20):product(price){cout?<<?"MP3"?<<?endl;}??
  • ????~MP3(){cout?<<?"~MP3"?<<?endl;}??
  • ????void?play(){??
  • ????????cout?<<?"use?to?listening?music"?<<?endl;??
  • ????}??
  • };???
  • ??
  • class?vedio:virtual?public?product{??
  • public:??
  • ????vedio(double?price?=?0):product(price){cout?<<?"vedio"?<<?endl;}??
  • ????~vedio(){cout?<<?"~vedio"?<<?endl;}??
  • ????void?vcd(){??
  • ????????cout?<<?"watch?vedio"?<<?endl;??
  • ????}???
  • };??
  • class?iphone:virtual?public?phone,virtual?public?MP3,virtual?public?vedio{??
  • public:??
  • ????iphone(int?m?=?0,int?v?=?0,int?p?=?0):product(m?+?p?+?v){}??
  • };??
  • /*虛函數(shù)之后,product的構(gòu)造函數(shù)只被調(diào)用了一次,孫子類(lèi)直接越級(jí)訪問(wèn)?
  • 了product類(lèi)*/??
  • int?main(){??
  • ????iphone?iphone6(1000,2041,3201);??
  • ????//cout?<<?iphone6.getprice()?<<?endl;同樣會(huì)產(chǎn)生沖突的問(wèn)題??
  • ????//cout?<<?sizeof(iphone)?<<?endl;??
  • ????//cout?<<?iphone6.MP3::getprice()?<<?endl;??
  • ????//cout?<<?iphone6.phone::getprice()?<<?endl;??
  • ????//cout?<<?iphone6.getprice()?<<?endl;直接調(diào)用產(chǎn)生沖突問(wèn)題,編譯器不知道該調(diào)用哪一個(gè)??
  • ????cout?<<?sizeof(iphone)?<<?endl;??
  • ????cout?<<?iphone6.getprice()?<<?endl;??
  • }??
  • /*類(lèi)中也會(huì)有對(duì)齊和補(bǔ)齊*/ #include <iostream> using namespace std; /*抽象到更高層的類(lèi)中*/ class product{int price; public:int getprice(){return price;}product(double price = 0):price(price){cout << "product" << endl;} };class phone:virtual public product{ public://phone();phone(double price = 15):product(price){cout << "phone" << endl;}~phone(){cout << "~phone" << endl;}void call(){cout << "use calling" << endl;} };class MP3:virtual public product{ public:MP3(double price = 20):product(price){cout << "MP3" << endl;}~MP3(){cout << "~MP3" << endl;}void play(){cout << "use to listening music" << endl;} }; class vedio:virtual public product{ public:vedio(double price = 0):product(price){cout << "vedio" << endl;}~vedio(){cout << "~vedio" << endl;}void vcd(){cout << "watch vedio" << endl;} }; class iphone:virtual public phone,virtual public MP3,virtual public vedio{ public:iphone(int m = 0,int v = 0,int p = 0):product(m + p + v){} }; /*虛函數(shù)之后,product的構(gòu)造函數(shù)只被調(diào)用了一次,孫子類(lèi)直接越級(jí)訪問(wèn) 了product類(lèi)*/ int main(){iphone iphone6(1000,2041,3201);//cout << iphone6.getprice() << endl;同樣會(huì)產(chǎn)生沖突的問(wèn)題//cout << sizeof(iphone) << endl;//cout << iphone6.MP3::getprice() << endl;//cout << iphone6.phone::getprice() << endl;//cout << iphone6.getprice() << endl;直接調(diào)用產(chǎn)生沖突問(wèn)題,編譯器不知道該調(diào)用哪一個(gè)cout << sizeof(iphone) << endl;cout << iphone6.getprice() << endl; }


    這個(gè)代碼中product的構(gòu)造函數(shù)只調(diào)用了一次,說(shuō)明子類(lèi)直接越級(jí)訪問(wèn)了爺爺類(lèi)的數(shù)據(jù)。而對(duì)于父類(lèi)特有的子類(lèi)照常繼承,只是沒(méi)有通過(guò)父類(lèi)去繼承爺爺類(lèi)的數(shù)據(jù)成員,所以product的構(gòu)造函數(shù)只被調(diào)用了一次。


    虛函數(shù):在函數(shù)前面加上virtual關(guān)鍵字修飾過(guò)的就是虛函數(shù).

    #include <iostream>
    using namespace std;
    class A{
    int x;
    public:
    virtual void show(){}
    virtual void showa(){}
    };
    int main(){
    cout << sizeof(A) << endl;
    }

    虛函數(shù)的主要表現(xiàn)為會(huì)占用四個(gè)字節(jié)的空間,只要成員中出現(xiàn)虛函數(shù),不管有多少個(gè)虛函數(shù),都只用四個(gè)字節(jié)來(lái)維護(hù)這個(gè)虛關(guān)系。虛函數(shù)會(huì)影響對(duì)象的大小。維護(hù)虛關(guān)系使用一個(gè)指針來(lái)維護(hù)的,所以是四個(gè)字節(jié)。


    函數(shù)重寫(xiě):

    在父類(lèi)中出現(xiàn)一個(gè)虛函數(shù),如果在子類(lèi)中提供和父類(lèi)同名的函數(shù)(注意區(qū)分名字隱藏),這就加函數(shù)重寫(xiě)。

    函數(shù)重寫(xiě)要求必須有相同函數(shù)名,相同的參數(shù)列表,相同的返回值。


    三、c++面向?qū)ο笾鄳B(tài)

    1、多態(tài):一個(gè)父類(lèi)型的對(duì)象的指針或者引用指向或者是引用一個(gè)子類(lèi)對(duì)象時(shí),調(diào)用父類(lèi)型中的虛函數(shù),如果子類(lèi)覆蓋了虛函數(shù),則調(diào)用的表現(xiàn)是子類(lèi)覆蓋之后的。

    繼承是構(gòu)成多態(tài)的基礎(chǔ);

    虛函數(shù)是構(gòu)成多態(tài)的關(guān)鍵;

    函數(shù)覆蓋是構(gòu)成多態(tài)的必備條件;

    多態(tài)的應(yīng)用:函數(shù)參數(shù),函數(shù)返回值。

    多態(tài)的產(chǎn)生必須依靠上面的四點(diǎn),缺一不可。


    2、多態(tài)的應(yīng)用,多態(tài)相對(duì)做到了通用類(lèi)型編程,主要用在函數(shù)參數(shù)和函數(shù)的返回值上。

    [cpp] view plain copy print?
  • /*多態(tài)的應(yīng)用:?
  • 1、函數(shù)參數(shù)?
  • 2、函數(shù)返回值*/??
  • #include?<iostream>??
  • using?namespace?std;??
  • class?Animal{??
  • public:??
  • ????virtual?void?run(){??
  • ????????cout?<<"Ainimal?run()"<<endl;??
  • ????}??
  • ????void?show(){??
  • ????????cout?<<"Animal?show()"<<endl;??
  • ????}??
  • };??
  • ??
  • class?Dog:public?Animal{??
  • public:??
  • ????void?run(){??
  • ????????cout?<<"Dog?run()"<<endl;??
  • ????}??
  • ????void?show(){??
  • ????????cout?<<"dog?show()"<<endl;??
  • ????}??
  • };??
  • ??
  • class?Cat:public?Animal{??
  • public:??
  • ????void?run(){??
  • ????????cout?<<"cat?run()"<<endl;??
  • ????}??
  • };??
  • /*多態(tài)用作函數(shù)參數(shù)*/??
  • void?showAnimal(Animal?*?animal){??
  • ????animal->show();??
  • ????animal->run();??
  • }??
  • /*多態(tài)用作返回值*/??
  • Animal?*?getAnimal(int?x){??
  • ????if?(1?==?x)??
  • ????????return?new?Dog();??
  • ????if?(2?==?x)??
  • ????????return?new?Cat();??
  • }??
  • int?main(){??
  • ????Cat?cat;??
  • ????showAnimal(&cat);??
  • ????Dog?dog;??
  • ????showAnimal(&dog);??
  • }??
  • /*多態(tài)的應(yīng)用: 1、函數(shù)參數(shù) 2、函數(shù)返回值*/ #include <iostream> using namespace std; class Animal{ public:virtual void run(){cout <<"Ainimal run()"<<endl;}void show(){cout <<"Animal show()"<<endl;} };class Dog:public Animal{ public:void run(){cout <<"Dog run()"<<endl;}void show(){cout <<"dog show()"<<endl;} };class Cat:public Animal{ public:void run(){cout <<"cat run()"<<endl;} }; /*多態(tài)用作函數(shù)參數(shù)*/ void showAnimal(Animal * animal){animal->show();animal->run(); } /*多態(tài)用作返回值*/ Animal * getAnimal(int x){if (1 == x)return new Dog();if (2 == x)return new Cat(); } int main(){Cat cat;showAnimal(&cat);Dog dog;showAnimal(&dog); }


    3、多態(tài)的實(shí)現(xiàn)原理

    多態(tài)的實(shí)現(xiàn)主要依賴(lài)于下面的三個(gè)東西:

    虛函數(shù):成員函數(shù)加了virtual修飾

    虛函數(shù)表指針:一個(gè)類(lèi)型有虛函數(shù),則對(duì)這個(gè)類(lèi)型提供一個(gè)指針,這個(gè)指針?lè)旁谏蓪?duì)象的前四個(gè)字節(jié)。同類(lèi)型的對(duì)象共享一張?zhí)摵瘮?shù)表。并且不同類(lèi)型的虛函數(shù)表地址不同。

    虛函數(shù)表:虛函數(shù)表中的每個(gè)元素都是虛函數(shù)的地址。

    一個(gè)類(lèi)型一旦出現(xiàn)虛函數(shù),則會(huì)生成一張?zhí)摵瘮?shù)表,虛函數(shù)表中存放的就是虛函數(shù)的函數(shù)地址,通過(guò)這個(gè)函數(shù)地址可以到代碼區(qū)中去執(zhí)行對(duì)應(yīng)的函數(shù)。虛函數(shù)表中只存放類(lèi)型中的虛函數(shù),不是虛函數(shù)的一概不管。在每個(gè)生成的類(lèi)型對(duì)象的前四個(gè)字節(jié)中存放的是虛函數(shù)表指針,通過(guò)這個(gè)指針可以訪問(wèn)到虛函數(shù)表,從而訪問(wèn)其中的函數(shù)。同種類(lèi)型共享虛函數(shù)表,不同類(lèi)型有自己獨(dú)立的虛函數(shù)表,繼承關(guān)系中的子類(lèi)和父類(lèi)屬于不同類(lèi)型,所以有自己獨(dú)立的函數(shù)表。


    [cpp] view plain copy print?
  • /*多態(tài)的原理*/??
  • #include?<iostream>??
  • #include?<cstring>??
  • using?namespace?std;??
  • class?Animal{??
  • ????int?x;??
  • public:??
  • ????virtual?void?fun(){??
  • ????????cout<<?"Aniaml?fun()"<<endl;??
  • ????}??
  • ????virtual?void?run(){??
  • ????????cout?<<"Animal?run()"<<endl;??
  • ????}??
  • ????void?show(){??
  • ????????cout?<<"Animal?show()"<<endl;??
  • ????}??
  • };??
  • ??
  • class?Dog:public?Animal{??
  • public:??
  • ????virtual?void?fun(){??
  • ????????cout?<<?"dog?run"<<endl;??
  • ????}??
  • ????void?run(){??
  • ????????cout?<<"dog?run"<<endl;??
  • ????}??
  • };??
  • ??
  • class?Cat:public?Animal{??
  • public:??
  • ????void?fun(){??
  • ????????cout?<<"cat?fun"<<endl;??
  • ????}??
  • };??
  • ??
  • int?main(){??
  • ????Animal?a;??
  • ????Animal?b;??
  • ????/*取出虛函數(shù)表的地址并打印*/??
  • ????int?*?pi?=?(int*)&a;??
  • ????cout?<<showbase<<?hex?<<?*pi<<endl;??
  • ??
  • ????pi?=?reinterpret_cast<int*>(&b);??
  • ????cout?<<showbase<<?hex?<<?*pi<<endl;??
  • ??
  • ????/*子類(lèi)不會(huì)和父類(lèi)共享虛函數(shù)表,地址不一樣*/??
  • ????Dog?dog;??
  • ????pi?=?reinterpret_cast<int*>(&dog);??
  • ????cout?<<showbase<<?hex?<<?*pi<<endl;??
  • ??
  • ????Animal?*?pcat?=?new?Cat();??
  • ????pcat->run();??
  • ????pcat->fun();??
  • ??
  • ????/*更改dog的虛表的值,我們把dog的虛表地址?
  • ????改成cat的虛表地址*/??
  • ????Animal?*?pdog?=?new?Dog();??
  • ????pdog->run();??
  • ????pdog->fun();??
  • ??
  • ????/*更換dog的虛表地址,將cat的前四個(gè)字節(jié)?
  • ????移動(dòng)到dog的前四個(gè)字節(jié)*/??
  • ????memcpy(pdog,pcat,4);??
  • ????pdog->run();??
  • ????pdog->fun();??
  • ????/*上面的更改后,狗變成了貓的特性*/??
  • }??
  • /*多態(tài)的原理*/ #include <iostream> #include <cstring> using namespace std; class Animal{int x; public:virtual void fun(){cout<< "Aniaml fun()"<<endl;}virtual void run(){cout <<"Animal run()"<<endl;}void show(){cout <<"Animal show()"<<endl;} };class Dog:public Animal{ public:virtual void fun(){cout << "dog run"<<endl;}void run(){cout <<"dog run"<<endl;} };class Cat:public Animal{ public:void fun(){cout <<"cat fun"<<endl;} };int main(){Animal a;Animal b;/*取出虛函數(shù)表的地址并打印*/int * pi = (int*)&a;cout <<showbase<< hex << *pi<<endl;pi = reinterpret_cast<int*>(&b);cout <<showbase<< hex << *pi<<endl;/*子類(lèi)不會(huì)和父類(lèi)共享虛函數(shù)表,地址不一樣*/Dog dog;pi = reinterpret_cast<int*>(&dog);cout <<showbase<< hex << *pi<<endl;Animal * pcat = new Cat();pcat->run();pcat->fun();/*更改dog的虛表的值,我們把dog的虛表地址改成cat的虛表地址*/Animal * pdog = new Dog();pdog->run();pdog->fun();/*更換dog的虛表地址,將cat的前四個(gè)字節(jié)移動(dòng)到dog的前四個(gè)字節(jié)*/memcpy(pdog,pcat,4);pdog->run();pdog->fun();/*上面的更改后,狗變成了貓的特性*/ }


    上述程序?qū)?yīng)的內(nèi)存圖:


    可以看出,一旦滿(mǎn)足了多態(tài)的條件,程序自然按照上圖的流程執(zhí)行。

    4、上面既然說(shuō)了,虛函數(shù)表中存放的是函數(shù)的地址,那么能不能直接我們自己取出虛函數(shù)的地址,直接調(diào)用所需要的函數(shù)呢?

    [cpp] view plain copy print?
  • #include?<iostream>??
  • using?namespace?std;??
  • ??
  • class?Animal{??
  • public:??
  • ????virtual?void?run(int?x){??
  • ????????cout?<<"run?x="<<x<<endl;??
  • ????}??
  • ????virtual?void?fun(int?x){??
  • ????????cout?<<"fun?x="<<x<<endl;??
  • ????}??
  • ????void?show(){??
  • ????????cout?<<"this?is?show()"<<endl;??
  • ????}??
  • };??
  • ??
  • ??
  • int?main()??
  • {??
  • ????/*去掉函數(shù)名就是函數(shù)指針的類(lèi)型,指針簡(jiǎn)化操作*/??
  • ????typedef?void?(*MFUN)(Animal*?a,int?x);/*MFUN就是虛表中的函數(shù)指針類(lèi)型*/??
  • ??
  • ????typedef?MFUN*?VTABLE;//MFUN*就是虛表類(lèi)型??
  • ??
  • ????Animal?animal;??
  • ????VTABLE?vt?=?*((VTABLE*)&animal);??
  • ????/*虛函數(shù)表表現(xiàn)為函數(shù)指針數(shù)組*/??
  • ????vt[0](&animal,100);??
  • ????vt[1](&animal,123);??
  • ????return?0;??
  • }??
  • #include <iostream> using namespace std;class Animal{ public:virtual void run(int x){cout <<"run x="<<x<<endl;}virtual void fun(int x){cout <<"fun x="<<x<<endl;}void show(){cout <<"this is show()"<<endl;} };int main() {/*去掉函數(shù)名就是函數(shù)指針的類(lèi)型,指針簡(jiǎn)化操作*/typedef void (*MFUN)(Animal* a,int x);/*MFUN就是虛表中的函數(shù)指針類(lèi)型*/typedef MFUN* VTABLE;//MFUN*就是虛表類(lèi)型Animal animal;VTABLE vt = *((VTABLE*)&animal);/*虛函數(shù)表表現(xiàn)為函數(shù)指針數(shù)組*/vt[0](&animal,100);vt[1](&animal,123);return 0; }


    虛表中存放的就是虛函數(shù)的函數(shù)指針,可以理解為函數(shù)指針的數(shù)組,通過(guò)typedef將指針降級(jí)。


    5,虛析構(gòu)函數(shù)

    virtual關(guān)鍵字只能修飾成員函數(shù)或者析構(gòu)函數(shù),其他的函數(shù)都不行。

    當(dāng)我們用new創(chuàng)建一個(gè)指向子類(lèi)對(duì)象的父類(lèi)指針時(shí),例如Animal * animal = new Dog()時(shí),其中Animal時(shí)父類(lèi),Dog是子類(lèi),并且delete animal時(shí),其子類(lèi)對(duì)象的析構(gòu)函數(shù)不會(huì)被調(diào)用,只會(huì)調(diào)用父類(lèi)的析構(gòu)函數(shù)。所以就會(huì)遇到一個(gè)問(wèn)題,如果子類(lèi)對(duì)象有自己獨(dú)立的堆內(nèi)存時(shí),這部分內(nèi)存就無(wú)法釋放。這時(shí),我們只需要在父類(lèi)的析構(gòu)函數(shù)上用virtual修飾即可,子類(lèi)析構(gòu)函數(shù)就會(huì)被調(diào)用。

    [cpp] view plain copy print?
  • #include?<iostream>??
  • using?namespace?std;??
  • ??
  • class?Animal{??
  • public:??
  • ????Animal(){??
  • ????????cout?<<"Animal()"<<endl;??
  • ????}??
  • ????virtual?~Animal(){??
  • ????????cout?<<"~Animal()"<<endl;??
  • ????}??
  • };??
  • class?Dog:public?Animal{??
  • public:??
  • ????Dog(){??
  • ????????cout?<<"Dog()"<<endl;??
  • ????}??
  • ????~Dog(){??
  • ????????cout?<<"~Dog()"<<endl;??
  • ????}??
  • };??
  • int?main(){??
  • ????Animal?*?pa?=?new?Dog();??
  • ????delete?pa;??
  • ????/*子類(lèi)析構(gòu)函數(shù)的調(diào)用必然引發(fā)父類(lèi)析構(gòu)*/??
  • }??
  • #include <iostream> using namespace std;class Animal{ public:Animal(){cout <<"Animal()"<<endl;}virtual ~Animal(){cout <<"~Animal()"<<endl;} }; class Dog:public Animal{ public:Dog(){cout <<"Dog()"<<endl;}~Dog(){cout <<"~Dog()"<<endl;} }; int main(){Animal * pa = new Dog();delete pa;/*子類(lèi)析構(gòu)函數(shù)的調(diào)用必然引發(fā)父類(lèi)析構(gòu)*/ }


    虛析構(gòu)函數(shù)的應(yīng)用場(chǎng)景:

    當(dāng)父類(lèi)中有虛函數(shù)時(shí),應(yīng)該吧父類(lèi)的析構(gòu)函數(shù)定義成虛析構(gòu)函數(shù)。

    子類(lèi)和父類(lèi)中都有自己的堆內(nèi)存分配時(shí)。

    總結(jié)

    以上是生活随笔為你收集整理的c++面向对象三大特征封装、继承和多态知识总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。