簡體   English   中英

以下程序如何在c ++中工作?

[英]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_ptrstd::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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM