简体   繁体   中英

How does the below program work in c++?

I have just created 2 pointers which has undefined behavior and try to invoke a class member function which has no object created ?

I don't understand this?

#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) It's undefined behavior. Any behavior may happen.

B) Since you're not calling a virtual method, it's pretty easy to explain why the undefined behavior actually does this (and I've tested this under just about every compiler I could find).

In C++, calling a member method is equivalent (in practice if not in definition) of calling a member with a hidden 'this' variable. If the method is virtual, it has to go through the vftable, but not for a non-virtual method.

So

Foo::Bar(){}

is the rough equivalent of

Foo_Bar(Foo *this){}

and in the calling code

Foo *foo = new Foo();
foo->bar();

the second line is roughly the moral equivalent of

Foo_Bar(foo);

Now, there's some simplification going on here, and as I said, some of this may be implementation detail rather than specification. However, the behavior holds true (though relying upon it is an error).

But, given the preceding, look at an implementation:

void Foo::Bar(){printf("Hello, world!\n");}

and calling code:

Foo *foo = 0;
foo->Bar();

As we've said, this is roughly equivalent (since we're non-virtual) to:

Foo *foo = 0;
Foo::Bar(foo);

Which means that we're calling the equivalent of the following method:

void Foo_Bar(Foo* this)
{ printf("Hello, world\n"); }

Now, given this method, we're not actually dereffing the this pointer! So, it's pretty clear why, in this case, the method will work and not fail.

The practical upshot of this is that calling non-virtual methods on a null pointer, where the method doesn't deref an a member, will generally result in this observed behavior. But, relying upon any undefined behavior is, basically, evil.

When you do something that has undefined behavior, anything can happen -- including it appearing to work. It looks like that's what's happening to you in this case.

您需要使用new运算符。

You need to change:

void talk()

To:

virtual void talk()

If you want the function to be polymorphic. Also, you need to instantiate your objects as in:

Animal* a = new Animal;
Dog* d = new Dog;

Don't forget to free them before you return:

delete a;
a = 0; 

delete d;
d = 0;

In practice, you will want to use a boost::shared_ptr or std::auto_ptr as in:

std::auto_ptr<Animal> a(new Animal);
std::auto_ptr<Dog> b(new Dog);

The above will save you the need to call delete. Alternatively, you can use automatic storage:

Animal a;
Dog d;

With the above, you would use a.talk() and d.talk() instead of a->talk() and d->talk() .

I believe the reason your code works is because the talk() methods are not actually accessing any member variables of the class. In other words, you are not actually accessing the implicit this , which happens to be invalid.

I actually experienced this same issue before. My code was calling a member function of a null pointer and it reliably worked. I finally discovered the problem when I modified the function so that it actually attempted to access a member variable. After that change it reliably crashed.

I'm not sure if this is standard behavior or compiler specific. In my case I was using Microsoft Visual Studio 2008.

It's undefined behavior, so anything might happen.

It can be possible that it just prints the correct thing since the methods don't access any member variables of the objects they are called on (the memory where the objects supposedly live doesn't need to be accessed, so access violations don't necessarily occur).

Unless your compiler specifies this kind of behavior somewhere (which it most probably won't), you can of course not count on this to happen.

you call this non-static member method, you should construct the object of class, so you need:

 Animal * a =  new Animal();
 Dog * d = new Animal();

 d->talk();
 a->talk(); 

 delete a;
 delete d;

And to use Polymorphism, you should use virtual keyword before talk()

public:
virtual void talk()
  {
    cout<<"I am an animal"<<endl; 
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM