Eternal Learner
Eternal Learner

Reputation: 3870

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

Upvotes: 1

Views: 267

Answers (7)

kyoryu
kyoryu

Reputation: 13055

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.

Upvotes: 10

Mark Yin
Mark Yin

Reputation: 1

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

Upvotes: 0

sth
sth

Reputation: 229633

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.

Upvotes: 0

flashk
flashk

Reputation: 2493

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.

Upvotes: 0

Michael Aaron Safyan
Michael Aaron Safyan

Reputation: 95519

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

Upvotes: 0

Jerry Coffin
Jerry Coffin

Reputation: 490178

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.

Upvotes: 8

JRL
JRL

Reputation: 78003

You need to use the new operator.

Upvotes: 0

Related Questions