C++ 動態(tài)綁定和靜態(tài)綁定
首先明確四個名詞定義:
-
靜態(tài)類型:對象在聲明時的類型,編譯期就能確定
-
動態(tài)類型:指針或引用所指的對象的類型
-
靜態(tài)綁定:綁定的是靜態(tài)類型,依賴于對象的靜態(tài)類型
-
動態(tài)綁定:綁定的是動態(tài)類型,依賴于對象的動態(tài)類型
類的非虛函數(shù)都是靜態(tài)綁定,虛函數(shù)都是動態(tài)綁定。
下面代碼中,
#include <iostream>
using namespace std;
class Fruit
{
public:
void print(){cout << "Fruit::print()" << endl;}
virtual void process(){cout << "Fruit::process()" << endl;}
};
class Apple : public Fruit
{
public:
void print(){cout << "Apple::print()" << endl;}
virtual void process(){cout << "Apple::process()" << endl;}
};
class Pear : public Fruit
{
public:
void print(){cout << "Pear::print()" << endl;}
virtual void process(){cout << "Pear::process()" << endl;}
};
int main() {
Pear* pc = new Pear();
Apple* pb = new Apple();
Fruit* pa = new Fruit();
pa = pb;
pa->print();
pb->print();
pc->print();
pa->process();
pb->process();
pc->process();
return 0;
}
- pa的靜態(tài)類型是Fruit,動態(tài)類型先是pc指向的Pear,后被改成pb指向的Apple
- pb的靜態(tài)類型和動態(tài)類型都是Apple
- pb的靜態(tài)類型和動態(tài)類型都是Pear
代碼執(zhí)行的結(jié)果為:
Fruit::print()
Apple::print()
Pear::print()
Apple::process()
Apple::process()
Pear::process()
可以看到對于類中非虛函數(shù)的調(diào)用,是靜態(tài)類型決定的,在編譯器就能確定;而虛函數(shù)的調(diào)用,是動態(tài)類型決定的,在運行期才能確定。在運行期確定函數(shù)的調(diào)用,就是面向?qū)ο笾兴f的多態(tài)。
注意
《Effective C++》中建議
1.絕對不要重新定義繼承而來的非虛(non-virtual)函數(shù)
2.絕對不要重新定義一個繼承而來的virtual函數(shù)的缺省參數(shù)值,因為缺省參數(shù)值都是靜態(tài)綁定(為了執(zhí)行效率),而virtual函數(shù)卻是動態(tài)綁定。
#include <iostream>
using namespace std;
class Fruit
{
public:
void print(){cout << "Fruit::print()" << endl;}
virtual void process(int i = 1){cout << "Fruit::process(), i="<< i << endl;}
};
class Apple : public Fruit
{
public:
void print(){cout << "Apple::print()" << endl;}
virtual void process(int i = 10){cout << "Apple::process(), i="<< i << endl;}
};
class Pear : public Fruit
{
public:
void print(){cout << "Pear::print()" << endl;}
virtual void process(int i = 20){cout << "Pear::process(), i="<< i << endl;}
};
int main() {
Pear* pc = new Pear();
Apple* pb = new Apple();
Fruit* pa = pc;
pa = pb;
pa->print();
pb->print();
pc->print();
pa->process();
pb->process();
pc->process();
return 0;
}
Fruit::print()
Apple::print()
Pear::print()
Apple::process(), i=1
Apple::process(), i=10
Pear::process(), i=20
上面的代碼,pa的process函數(shù)調(diào)用的是子類的process,但是參數(shù)的默認值卻是父類的默認值。