繼承:可以使用原來的代碼,代碼復(fù)用
多態(tài):代碼復(fù)用、接口復(fù)用,用基類的指針“根據(jù)對(duì)象”調(diào)用“指定對(duì)象的函數(shù)”。
1、繼承、訪問修飾符
2、C++不是類型安全的語言
3、賦值兼容問題:類型轉(zhuǎn)換
4、
static與繼承在基類中定義的靜態(tài)成員,將被所有派生類共享;根據(jù)靜態(tài)成員自身的訪問特性和派生類的繼承方式,在類層次體系中具有不同的訪問屬性;派生類中訪問靜態(tài)成員,用下面形式:類名::成員 、 對(duì)象名.成員 。【討論:在父類和子類中聲明、定義同名的靜態(tài)變量b,子類中的b會(huì)不會(huì)覆蓋父類中的b】
#include <iostream>
using namespace std;
class B
{
public:B(){
cout<<
"&B::b = "<<&b<<endl; }
static int b;
};
class D:
public B
{
public:D(){
cout<<
"&D::b = "<<&b<<endl;
cout<<
"&B::b = "<<&B::b<<endl;}
static int b;
};
int D::b =
0;
int main()
{D d;
}
5、繼承中的構(gòu)造
①子類中的父類如何進(jìn)行初始化?答:用成員初始化列表調(diào)用父類的構(gòu)造函數(shù)進(jìn)行初始化子類中的父類。
②繼承與組合混搭的情況下,如何進(jìn)行構(gòu)造?答:構(gòu)造順序:基類、組合類、派生類
③繼承中同名成員變量的處理方法?
#include <iostream>
using namespace std;
class A
{
public:A(
int aa):a(aa){
cout<<
"A"<<endl;}
int get_A(){
return a;}
void show_A(){
cout<<
"a="<<a<<endl;}
protected:
private:
int a;
};
class B
{
public:B(
int bb):b(bb){
cout<<
"B"<<endl;}
int get_B(){
return b;}
void show_B(){
cout<<
"b="<<b<<endl;}
protected:
private:
char b;
};
class D:
public B
{
public:D(
int bb,
int dd,
int aa):a1(aa),B(bb),d(dd){
cout<<
"D"<<endl;}
void show_D(){a1.show_A();
cout<<
"b="<<get_B()<<endl<<
"d="<<d<<endl; }
protected:
private:
int d;A a1;
};
int main()
{D d(
1,
2,
3); d.show_D();
}
6、多繼承
#include <iostream>
using namespace std;
class A
{
public:
A(
int i=
1):a(i){}
int a;
private:};
class B
{
public:
B(
int i=
1):a(i){}
int a;
private:};
class C:
public A,
public B
{
public:
C(
int i=
0):A(i),B(i){}
};
int main()
{C c1;cout<<c1.A::a<<endl; cout<<c1.B::a<<endl;
} 虛繼承圖示見下:
7、多態(tài)(發(fā)生的條件)父類的指針或引用指向子類的對(duì)象,并調(diào)用子類重寫的父類的虛函數(shù)。
多態(tài)成立的3個(gè)條件:有繼承子類重寫父類的虛函數(shù)父類的指針或引用指向子類對(duì)象
【總結(jié)】
動(dòng)態(tài)聯(lián)編:當(dāng)有
virtual修飾時(shí),調(diào)用子類?父類?的函數(shù)由“____對(duì)象”決定!
靜態(tài)編譯:當(dāng)無
virtual修飾時(shí),調(diào)用子類?父類?的函數(shù)由“____指針”決定!
8、類與類之間的關(guān)系
1.組合:包含關(guān)系
2.關(guān)聯(lián):一個(gè)類部分的使用另外一個(gè)類。通過類之間成員函數(shù)的相互聯(lián)系,定義友元或?qū)ο髤?shù)傳遞實(shí)現(xiàn)。(了解)
3.繼承
4.友元類
9、多態(tài)面試題
①多態(tài)的實(shí)現(xiàn)效果:多態(tài):同樣的調(diào)用語句有多種不同的形態(tài)
②多態(tài)的三個(gè)條件:繼承、子類重寫父類的虛函數(shù)、父類指針或引用指向子類對(duì)象
③多態(tài)的C++實(shí)現(xiàn):虛函數(shù)表、虛函數(shù)指針、動(dòng)態(tài)綁定
virtual關(guān)鍵字,告訴C++編譯器要進(jìn)行“遲綁定”的動(dòng)態(tài)聯(lián)編;不要根據(jù)指針類型判斷如何調(diào)用,而是要根據(jù)指針?biāo)赶虻膶?shí)際對(duì)象類型來判斷如何調(diào)用。
④多態(tài)的理論基礎(chǔ):動(dòng)態(tài)聯(lián)編PK靜態(tài)聯(lián)編,根據(jù)實(shí)際的對(duì)象類型來判斷重寫函數(shù)的調(diào)用。
⑤多態(tài)的重要意義:設(shè)計(jì)模式的基礎(chǔ)
⑥實(shí)現(xiàn)多態(tài)的理論基礎(chǔ):函數(shù)指針作函數(shù)參數(shù)
#include <iostream>
using namespace std;
class B
{
public:
virtual void f(
int i) { }
};
class D:
public B
{
public:
void f(
int i) { }
};
void g(B& b)
{b.f(
1);
}
void g(B* b)
{b->f(
1);
}
void main()
{D dd;g(dd); g(&dd);
}
以上面代碼為例,分析一下要實(shí)現(xiàn)多態(tài),C++編譯器應(yīng)該動(dòng)什么手腳?
①第一個(gè)動(dòng)手腳的地方:
virtual void f(
int i)中的
virtual,動(dòng)了什么手腳?虛函數(shù)表、虛函數(shù)指針
②第二個(gè)動(dòng)手腳的地方:
void g(B& b)中的b,我們?cè)趺粗纻魅氲氖歉割惖膶?duì)象?還是子類的對(duì)象?傳入的對(duì)象中有一個(gè)虛函數(shù)表指針*Vptr,通過該虛函數(shù)表指針*Vptr找到對(duì)應(yīng)的虛函數(shù)表,之后再找到要調(diào)用的函數(shù)的函數(shù)指針,通過函數(shù)指針對(duì)函數(shù)進(jìn)行調(diào)用。因此,加上
virtual關(guān)鍵字聲明后的函數(shù)的調(diào)用結(jié)果是由“對(duì)象類型”決定的!C++中多態(tài)實(shí)現(xiàn)原理當(dāng)類中聲明虛函數(shù)時(shí),C++編譯器會(huì)在類中生成一個(gè)虛函數(shù)表虛函數(shù)表是一個(gè)存儲(chǔ)類成員函數(shù)指針的數(shù)據(jù)結(jié)構(gòu)虛函數(shù)表是由編譯器自動(dòng)生成和維護(hù)的
virtual成員函數(shù)會(huì)被編譯器放入虛函數(shù)表中存在虛函數(shù)表時(shí),每個(gè)對(duì)象中有一個(gè)指向虛函數(shù)表的指針(vptr指針)
【答案:面試題1、2】
【說明1】
通過虛函數(shù)表指針Vptr調(diào)用重寫函數(shù)是在程序運(yùn)行時(shí)進(jìn)行的,因此需要通過尋址操作才能確定真正應(yīng)該調(diào)用的函數(shù);而普通成員函數(shù)是在編譯時(shí)就確定了調(diào)用的函數(shù),因此:在效率上,虛函數(shù)的效率要低很多。
【說明2】
出于效率問題,沒有必要把所有的成員函數(shù)都聲明為虛函數(shù)。
【答案:面試題4】可以把所有的函數(shù)聲明為虛函數(shù),但是會(huì)降低代碼的執(zhí)行效率。因此,不使用多態(tài)時(shí),不要把函數(shù)聲明為虛函數(shù)。
父類中的虛函數(shù)表指針能否被子類繼承?
【答案:面試題
5】構(gòu)造函數(shù)中調(diào)用虛函數(shù)不能實(shí)現(xiàn)多態(tài)!
為什么不能?Vptr指針的初始化過程是分步完成的
1.構(gòu)造子類對(duì)象過程中,先執(zhí)行父類的構(gòu)造函數(shù),此時(shí)C++編譯會(huì)初始化子類的Vptr指針,讓Vptr指針暫時(shí)先指向父類的函數(shù)表。因此,在父類的構(gòu)造函數(shù)中調(diào)用虛函數(shù)
virtual void f(),此時(shí)調(diào)用的是父類中的f().
2.當(dāng)父類的構(gòu)造函數(shù)執(zhí)行完成后,再執(zhí)行子類的構(gòu)造函數(shù),此時(shí)C++編譯會(huì)重新修改子類的Vptr指針,讓Vptr指針真正的指向子類的函數(shù)表。同樣:析構(gòu)函數(shù)中調(diào)用虛函數(shù)不能實(shí)現(xiàn)多態(tài)!
#include <iostream>
using namespace std;
class B
{
public:B(){f();}
virtual void f() {
cout<<
"父類"<<endl; }
virtual ~B(){f();}
};
class D:
public B
{
public:D(){}
virtual void f() {
cout<<
"子類"<<endl; }~D(){}
};
int main()
{D d;
return 0;
}
【答案:面試題
8】
#include <iostream>
using namespace std;
class A
{
public:
virtual ~A(){
cout<<
"析構(gòu)父類A"<<endl;}
};
class B:
public A
{
public:~B(){
cout<<
"析構(gòu)子類B"<<endl;}
};
int main()
{A *p =
new B;
delete p;
}
總結(jié)
以上是生活随笔為你收集整理的第九天2017/04/18(2、类的继承、面试题:继承访问修饰符、组合、static、构造、多态)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。