您好,登錄后才能下訂單哦!
父子間的賦值兼容--子類對象可以當作父類對象使用(兼容性)
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;
}
對該代碼進行結果預測:通過之前的學習的同名覆蓋,程序會在 rp.add(5); rp.add(10, 10); 進行同名覆蓋,且在父類指針指向子類對象時可以進行調用
運行結果
通過程序的運行結果看到,與預測的結果不同,這是因為當使用父類指針(引用)指向子類對象時
1.子類對象退化為父類對象--所以在pp->mv時會出錯
2.只能訪問父類中定義的成員
3.可以直接訪問被子類覆蓋的同名成員--所以沒發生同名覆蓋
特殊的同名函數
1.子類中可以重定義父類中已經存在的成員函數
2.這種重定義發生在繼承中,叫做函數重寫
3.函數重寫是同名覆蓋的一種特殊情況
Q:當函數重寫遇上賦值兼容會發生什么?
代碼示例
#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;
}
輸出結果
問題分析
1.編譯期間,編譯器只能根據指針的類型判斷所指向的對象
2.根據賦值兼容,編譯器認為父類指針指向的是父類對象
3.因此,編譯結果只可能是調用父類中定義的同名函數
在編譯這個函數的時候,編譯器不可能知道指針p指向了什么,但是編譯器沒有理由報錯。于是,編譯器認為最安全的做法時調用父類的print函數,因為父類和子類肯定都有相同的print函數
函數重寫
1.父類中被重寫的函數依然會繼承給子類
2.子類中重寫的函數將覆蓋父類中的函數
3.通過作用域分辨符(::)可以訪問父類中的函數
A.面向對象中期待的行為
1.根據實際的對象類型判斷如何調用重寫函數
2.父類指針指向--a.父類對象調用父類中定義的函數b.子類對象則調用子類中定義的函數
B.面向對象的多態的概念
1.根據實際的對象類型決定函數調用的具體目標
2.同樣的調用語句在實際運行時有多種不同的表現形態
C.C++語言中直接支持多態的概念
1.通過使用virtual關鍵字對多態進行支持
2.被virtual聲明的函數被重寫后具有多態特性
3.被virtual聲明的函數叫做虛函數
#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(); // 展現多態的行為
}
int main()
{
Parent p;
Child c;
how_to_print(&p);
how_to_print(&c);
return 0;
}
運行結果
D.多態的意義
1.在程序的運行過程中展現出多態的特性
2.函數重寫必須實現多態,否則沒有意義
3.多態時面向對象組件化程序設計的基礎特性
靜態聯編--在程序的編譯期間就能確定具體的函數調用
動態聯編--在程序實際運行后才能確定具體的函數調用
#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); // 展現多態的特性
// 動態聯編
}
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;
}
運行結果
小結
1.函數重寫只可能發生在父類與子類之間
2.根據實際對象的類型確定調用的具體函數
3.virtual關鍵字是C++中支持多態的唯一方式
4.被重寫的虛函數表現出多態的特性
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。