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