[英]How does the below program work in c++?
我剛剛創建了2個具有未定義行為的指針,並嘗試調用沒有創建對象的類成員函數?
我不明白嗎
#include<iostream>
using namespace std;
class Animal
{
public:
void talk()
{
cout<<"I am an animal"<<endl;
}
};
class Dog : public Animal
{
public:
void talk()
{
cout<<"bark"<<endl;
}
};
int main()
{
Animal * a;
Dog * d;
d->talk();
a->talk();
}
A)這是未定義的行為。 任何行為都可能發生。
B)因為您沒有調用虛擬方法,所以很容易解釋為什么未定義的行為實際上會這樣做(而且我已經在我能找到的幾乎所有編譯器中進行了測試)。
在C ++中,調用成員方法等效於(實際上,如果沒有定義)調用帶有隱藏的“ this”變量的成員。 如果該方法是虛擬的,則必須通過vftable進行操作,但對於非虛擬方法則不需要。
所以
Foo::Bar(){}
大致相當於
Foo_Bar(Foo *this){}
並在調用代碼中
Foo *foo = new Foo();
foo->bar();
第二行大致相當於
Foo_Bar(foo);
現在,這里進行了一些簡化,正如我所說,其中一些可能是實現細節而不是規范。 但是,該行為成立(盡管依賴它是一個錯誤)。
但是,鑒於上述內容,請看一個實現:
void Foo::Bar(){printf("Hello, world!\n");}
和調用代碼:
Foo *foo = 0;
foo->Bar();
正如我們所說,這大致等效於(因為我們不是虛擬的):
Foo *foo = 0;
Foo::Bar(foo);
這意味着我們正在調用以下方法的等效項:
void Foo_Bar(Foo* this)
{ printf("Hello, world\n"); }
現在,使用此方法,我們實際上並沒有延遲this指針! 因此,很明顯為什么在這種情況下該方法將起作用而不會失敗。
實際的結果是,在空指針上調用非虛擬方法(該方法不會取消引用成員)通常會導致這種觀察到的行為。 但是,依靠任何未定義的行為基本上是邪惡的。
當您執行某些行為未定義時, 任何事情都可能發生-包括它似乎起作用。 在這種情況下,這似乎就是您正在發生的事情。
您需要使用new
運算符。
您需要更改:
void talk()
至:
virtual void talk()
如果您希望函數是多態的。 另外,您需要按以下方式實例化對象:
Animal* a = new Animal; Dog* d = new Dog;
返回之前,請不要忘記釋放它們:
delete a; a = 0; delete d; d = 0;
實際上,您將需要使用boost::shared_ptr
或std::auto_ptr
如下所示:
std::auto_ptr<Animal> a(new Animal); std::auto_ptr<Dog> b(new Dog);
以上將節省您調用刪除的需要。 另外,您可以使用自動存儲:
Animal a; Dog d;
通過以上操作,您將使用a.talk()
和d.talk()
代替a->talk()
和d->talk()
。
我相信您的代碼能夠正常工作的原因是talk()方法實際上並未訪問該類的任何成員變量。 換句話說,您實際上並沒有訪問隱式的this ,而這恰好是無效的。
我實際上曾經遇到過同樣的問題。 我的代碼正在調用null指針的成員函數,並且可以可靠地工作。 我最終在修改函數時發現了問題,以便實際上嘗試訪問成員變量。 更改之后,它確實崩潰了。
我不確定這是標准行為還是特定於編譯器。 就我而言,我使用的是Microsoft Visual Studio 2008。
這是未定義的行為,因此可能會發生任何事情。
由於方法不訪問被調用的對象的任何成員變量,因此它可能只打印正確的內容(不需要訪問假定存在的對象的內存,因此不需要訪問沖突必然發生)。
除非您的編譯器在某處指定了這種行為(很可能不會),否則您當然不能指望這種情況會發生。
調用此非靜態成員方法時,應構造類的對象,因此需要:
Animal * a = new Animal();
Dog * d = new Animal();
d->talk();
a->talk();
delete a;
delete d;
要使用多態,您應該在talk()之前使用虛擬關鍵字
public:
virtual void talk()
{
cout<<"I am an animal"<<endl;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.