您好,登錄后才能下訂單哦!
父子間的賦值兼容--子類對象可以當(dāng)作父類對象使用(兼容性)
1.子類對象可以直接賦值給父類對象
2.子類對象可以直接初始化父類對象
3.父類指針可以指向子類對象
4.父類引用可以直接引用子類對象
代碼示例
#include <iostream>
#include <string>
using namespace std;
class Parent
{
public:
int mi;
void add(int i)
{
mi += i;
}
void add(int a, int b)
{
mi += (a + b);
}
};
class Child : public Parent
{
public:
int mv;
void add(int x, int y, int z)
{
mv += (x + y + z);
}
};
int main()
{
Parent p;
Child c;
p = c;
Parent p1(c);
Parent& rp = c;
Parent* pp = &c;
rp.mi = 100;
rp.add(5);
rp.add(10, 10);
pp->mv = 1000;
pp->add(1, 10, 100);
return 0;
}
對該代碼進(jìn)行結(jié)果預(yù)測:通過之前的學(xué)習(xí)的同名覆蓋,程序會在 rp.add(5); rp.add(10, 10); 進(jìn)行同名覆蓋,且在父類指針指向子類對象時可以進(jìn)行調(diào)用
運行結(jié)果
通過程序的運行結(jié)果看到,與預(yù)測的結(jié)果不同,這是因為當(dāng)使用父類指針(引用)指向子類對象時
1.子類對象退化為父類對象--所以在pp->mv時會出錯
2.只能訪問父類中定義的成員
3.可以直接訪問被子類覆蓋的同名成員--所以沒發(fā)生同名覆蓋
特殊的同名函數(shù)
1.子類中可以重定義父類中已經(jīng)存在的成員函數(shù)
2.這種重定義發(fā)生在繼承中,叫做函數(shù)重寫
3.函數(shù)重寫是同名覆蓋的一種特殊情況
Q:當(dāng)函數(shù)重寫遇上賦值兼容會發(fā)生什么?
代碼示例
#include <iostream>
#include <string>
using namespace std;
class Parent
{
public:
int mi;
void add(int i)
{
mi += i;
}
void add(int a, int b)
{
mi += (a + b);
}
void print()
{
cout << "I'm Parent." << endl;
}
};
class Child : public Parent
{
public:
int mv;
void add(int x, int y, int z)
{
mv += (x + y + z);
}
void print()
{
cout << "I'm Child." << endl;
}
};
void how_to_print(Parent* p)
{
p->print();
}
int main()
{
Parent p;
Child c;
how_to_print(&p);
how_to_print(&c);
return 0;
}
輸出結(jié)果
問題分析
1.編譯期間,編譯器只能根據(jù)指針的類型判斷所指向的對象
2.根據(jù)賦值兼容,編譯器認(rèn)為父類指針指向的是父類對象
3.因此,編譯結(jié)果只可能是調(diào)用父類中定義的同名函數(shù)
在編譯這個函數(shù)的時候,編譯器不可能知道指針p指向了什么,但是編譯器沒有理由報錯。于是,編譯器認(rèn)為最安全的做法時調(diào)用父類的print函數(shù),因為父類和子類肯定都有相同的print函數(shù)
函數(shù)重寫
1.父類中被重寫的函數(shù)依然會繼承給子類
2.子類中重寫的函數(shù)將覆蓋父類中的函數(shù)
3.通過作用域分辨符(::)可以訪問父類中的函數(shù)
A.面向?qū)ο笾衅诖男袨?/strong>
1.根據(jù)實際的對象類型判斷如何調(diào)用重寫函數(shù)
2.父類指針指向--a.父類對象調(diào)用父類中定義的函數(shù)b.子類對象則調(diào)用子類中定義的函數(shù)
B.面向?qū)ο蟮亩鄳B(tài)的概念
1.根據(jù)實際的對象類型決定函數(shù)調(diào)用的具體目標(biāo)
2.同樣的調(diào)用語句在實際運行時有多種不同的表現(xiàn)形態(tài)
C.C++語言中直接支持多態(tài)的概念
1.通過使用virtual關(guān)鍵字對多態(tài)進(jìn)行支持
2.被virtual聲明的函數(shù)被重寫后具有多態(tài)特性
3.被virtual聲明的函數(shù)叫做虛函數(shù)
#include <iostream>
#include <string>
using namespace std;
class Parent
{
public:
virtual void print()
{
cout << "I'm Parent." << endl;
}
};
class Child : public Parent
{
public:
void print()
{
cout << "I'm Child." << endl;
}
};
void how_to_print(Parent* p)
{
p->print(); // 展現(xiàn)多態(tài)的行為
}
int main()
{
Parent p;
Child c;
how_to_print(&p);
how_to_print(&c);
return 0;
}
運行結(jié)果
D.多態(tài)的意義
1.在程序的運行過程中展現(xiàn)出多態(tài)的特性
2.函數(shù)重寫必須實現(xiàn)多態(tài),否則沒有意義
3.多態(tài)時面向?qū)ο蠼M件化程序設(shè)計的基礎(chǔ)特性
靜態(tài)聯(lián)編--在程序的編譯期間就能確定具體的函數(shù)調(diào)用
動態(tài)聯(lián)編--在程序?qū)嶋H運行后才能確定具體的函數(shù)調(diào)用
#include <iostream>
#include <string>
using namespace std;
class Parent
{
public:
virtual void func()
{
cout << "void func()" << endl;
}
virtual void func(int i)
{
cout << "void func(int i) : " << i << endl;
}
virtual void func(int i, int j)
{
cout << "void func(int i, int j) : " << "(" << i << ", " << j << ")" << endl;
}
};
class Child : public Parent
{
public:
void func(int i, int j)
{
cout << "void func(int i, int j) : " << i + j << endl;
}
void func(int i, int j, int k)
{
cout << "void func(int i, int j, int k) : " << i + j + k << endl;
}
};
void run(Parent* p)
{
p->func(1, 2); // 展現(xiàn)多態(tài)的特性
// 動態(tài)聯(lián)編
}
int main()
{
Parent p;
p.func();
p.func(1);
p.func(1, 2);
cout << endl;
Child c;
c.func(1, 2);
cout << endl;
run(&p);
run(&c);
return 0;
}
運行結(jié)果
小結(jié)
1.函數(shù)重寫只可能發(fā)生在父類與子類之間
2.根據(jù)實際對象的類型確定調(diào)用的具體函數(shù)
3.virtual關(guān)鍵字是C++中支持多態(tài)的唯一方式
4.被重寫的虛函數(shù)表現(xiàn)出多態(tài)的特性
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。