以下程序如何在c ++中运行?

时间:2010-04-02 04:04:15

标签: c++ class pointers

我刚刚创建了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();  
} 

7 个答案:

答案 0 :(得分:10)

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"); }

现在,给定这个方法,我们实际上并没有使这个指针失效!因此,很明显为什么,在这种情况下,该方法将起作用而不会失败。

这方面的实际结果是,在空指针上调用非虚方法,其中方法不解析成员,通常会导致这种观察到的行为。但是,依赖于任何未定义的行为,基本上都是邪恶的。

答案 1 :(得分:8)

当您执行具有未定义行为的操作时,任何都可能发生 - 包括它似乎正常工作。看起来这就是在这种情况下发生的事情。

答案 2 :(得分:0)

您需要使用new运算符。

答案 3 :(得分:0)

您需要更改:

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()

答案 4 :(得分:0)

我相信你的代码工作的原因是因为talk()方法实际上并没有访问类的任何成员变量。换句话说,您实际上并没有访问隐含的 this ,这恰好是无效的。

我以前经历过同样的问题。我的代码调用了一个空指针的成员函数,它可靠地工作。当我修改函数以便它实际上试图访问成员变量时,我终于发现了这个问题。在那次改变之后,它可靠地崩溃了。

我不确定这是标准行为还是特定于编译器。就我而言,我使用的是Microsoft Visual Studio 2008。

答案 5 :(得分:0)

这是未定义的行为,所以任何事情都可能发生。

它可能只是打印正确的东西,因为方法不访问它们被调用的对象的任何成员变量(不需要访问所谓的生存对象的内存,因此访问违规不一定会发生。)

除非你的编译器在某个地方指定这种行为(它很可能不会这样做),你当然不能指望这种情况发生。

答案 6 :(得分:0)

你调用这个非静态成员方法,你应该构造类的对象,所以你需要:

 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; 
  }