概念
當一個子類對象通過值傳遞給基類對象,如foo(Base derived_obj),這個基類的拷貝構造函數將被調用.此時子類的特性將被切割,只有基類相關操作. 也就是說如果我們向上轉型如果不用引用或指針,對象將被切割.這是也我們應該傳引用而不是傳值的原因.
示例代碼:
[cpp]
#include <iostream>
#include <string>
using namespace std;
class Animal{
public:
Animal(const string& s) : name(s) {}
virtual void eat() const {
cout << "animal: " << name << " eat()" << endl;
}
private:
string name;
};
class Bird : public Animal {
private:
string name;
string habitat;
public:
Bird(const string& sp, const string &s, const string &h)
: Animal(sp), name(s), habitat(h) {};
virtual void eat() const {
cout << "bird: " << name << " eat() in " << habitat << endl;
}
};
void WhatAreYouDoingValue(Animal a) {
a.eat();
}
void WhatAreYouDoingReference(const Animal &a) {
a.eat();
}
int main()
{
Animal animal("Animal");
Bird bird("Eagle","Bald","US and Canada");
cout << "pass-by-value" << endl;
WhatAreYouDoingValue(animal);
WhatAreYouDoingValue(bird);
cout << "\npass-by-reference" << endl;
WhatAreYouDoingReference(animal);
WhatAreYouDoingReference(bird);
}
輸出結果如下:
pass-by-value
animal: Animal eat()
animal: Eagle eat()
pass-by-reference
animal: Animal eat()
bird: Bald eat() in US and Canada
分析:
注意,我們在main()函數中調用了兩個函數,WhatAreYouDoingValue(Animal a)與WhatAreYouDoingReference(constAnimal &a).第一個調用是能過傳值,第二個調用是傳引用.
我們可能希望第一個調用輸出 animal:Animal eat(),第二個調用輸出bird: Bald eat() in US and Canada.事實上兩個都是調用基類的eat.www.2cto.com
為什麼呢?
在傳值例子中,因為eat()是被Animal 的對象執行的object.這樣倒至Animal對象被進行壓棧操作.這樣就造成如果是值傳遞調用Animal默認構造函數,初始化vptr通過Animal類的vtbl並且只拷貝Animal部分.所以結果只剩下Animal部分了。
作者:wpf_ml