C++ 動(dòng)態(tài)綁定和靜態(tài)綁定
首先明確四個(gè)名詞定義:
-
靜態(tài)類(lèi)型:對(duì)象在聲明時(shí)的類(lèi)型骇两,編譯期就能確定
-
動(dòng)態(tài)類(lèi)型:指針或引用所指的對(duì)象的類(lèi)型
-
靜態(tài)綁定:綁定的是靜態(tài)類(lèi)型,依賴(lài)于對(duì)象的靜態(tài)類(lèi)型
-
動(dòng)態(tài)綁定:綁定的是動(dòng)態(tài)類(lèi)型巍糯,依賴(lài)于對(duì)象的動(dòng)態(tài)類(lèi)型
類(lèi)的非虛函數(shù)都是靜態(tài)綁定呻右,虛函數(shù)都是動(dòng)態(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)類(lèi)型是Fruit漩蟆,動(dòng)態(tài)類(lèi)型先是pc指向的Pear垒探,后被改成pb指向的Apple
- pb的靜態(tài)類(lèi)型和動(dòng)態(tài)類(lèi)型都是Apple
- pb的靜態(tài)類(lèi)型和動(dòng)態(tài)類(lèi)型都是Pear
代碼執(zhí)行的結(jié)果為:
Fruit::print()
Apple::print()
Pear::print()
Apple::process()
Apple::process()
Pear::process()
可以看到對(duì)于類(lèi)中非虛函數(shù)的調(diào)用,是靜態(tài)類(lèi)型決定的怠李,在編譯器就能確定圾叼;而虛函數(shù)的調(diào)用,是動(dòng)態(tài)類(lèi)型決定的扔仓,在運(yùn)行期才能確定褐奥。在運(yùn)行期確定函數(shù)的調(diào)用,就是面向?qū)ο笾兴f(shuō)的多態(tài)翘簇。
注意
《Effective C++》中建議
1.絕對(duì)不要重新定義繼承而來(lái)的非虛(non-virtual)函數(shù)
2.絕對(duì)不要重新定義一個(gè)繼承而來(lái)的virtual函數(shù)的缺省參數(shù)值撬码,因?yàn)槿笔?shù)值都是靜態(tài)綁定(為了執(zhí)行效率),而virtual函數(shù)卻是動(dòng)態(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)用的是子類(lèi)的process,但是參數(shù)的默認(rèn)值卻是父類(lèi)的默認(rèn)值彻犁。