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