Question

I'm still learning C++; I was trying out how polymorphism works and I got a segmentation fault when calling a virtual method.

(Note: I didn't mark the destructor as virtual, I was just trying out to see what happens.) Here's the code:

#include <iostream>

using namespace std;

class Base
{
protected:
  char *name;

public:
  Base(char *name)
  {
    cout << name << ": Base class cons" << endl;
  }

  ~Base()
  {
    cout << name << ": Base class des" << endl;
  }

  virtual void disp();
};

void Base::disp()
{
  cout << name << ": Base disp()" << endl;
}

class Child : public Base
{
public:
  Child(char *name):
    Base(name)
  {
    cout << name << ": Child class cons" << endl;
  }

  ~Child()
  {
    cout << name << ": Child class des" << endl;
  }

  virtual void disp()
  {
    cout << name << ": Child disp()" << endl;
  }
};


int main()
{
  //Base b;
  //b.disp();
  Base c = Child("2");
  c.disp();
}

Also, if you've any other tips regarding the usage of inheritance and polymorphism in general for someone who knows these concepts in Java, please let me know. Thank you!

Was it helpful?

Solution

name - is unintialized in Base

also you have another problem:

  Base c = Child("2");

I don't think it's what you want. Your code will create an instance of Base from casted Child. But I think you want work with Child instance based on Base interface; you should instead write:

  Base *c = new Child("2");

also, to avoid future bugs, declare destructor in base as virtual.

OTHER TIPS

You never initialise the base nenber variable - your base constructor should be:

Base(char * aname) : name( aname )
  {
    cout << name << ": Base class cons" << endl;
  }

As well as that, when you say

Base b = Child( "xxx" );

then the Child instance will be sliced down to a Base, which is probably not what you want.

I don't think you're assigning the member char * name to anything in your ctors.

The Child::disp() method will never be called - c is a variable of type Base, and not a pointer or reference, so it won't check for virtual methods.

Base * c = new Child("1");
c->disp();
delete c;

would call Child::disp().

Whoa there.

There's a few problems, but your segfault is probably because you're passing a char* -- which is just a pointer, and then trying to cout it in disp(). Problem is, that pointer does not live in disp(), it lives in main(). You probably want to either deep-copy the char*, or use std::string. Doing it this way will not work.

EDIT:

See EDIT 2

You can not just assign name to the class's name variable. If you do that, you'll get unpredictable results - and you'll probably STILL segfault. Remember: in C/C++, objects are locally scoped unless allocated on the heap. In this case, in your ctor, you'd want to do something like:

this->name = new char[ strlen( name ) + 1 ];
strcpy( this->name, name );

And in the destructor, you'll want to do something like:

delete [] this->name;

Note: my syntax may be completely wrong, and I realize the above code is inherently unsafe as you're not checking the char* to make sure it's not NULL, and you're not checking the return value of new. Nevertheless, this should get you started.

EDIT 2: I stand corrected. String literals are treated as constant storage and thus live on for the duration of the program. Nevertheless, the lesson, I believe, is important: in general, when not dealing with string literals, passing a pointer (or array, etc.), you need to allocate storage for it and deep-copy. You also need to de-allocate appropriately when destroying said object.

There are few problems here. The first thing is your base class destructor has to be virtual. Otherwise your base class destructor will always be called even if it points to derived object. Second is you should not assign derived class object to base class object. This is called object slicing. So, assignment should be done through pointer or reference.

The segmentation problem is happening because it contains garbage value. You need to initialize it in the constructor.

You have a couple of problems with your code.

First, and the reason why your getting a segfault, is the implementation of the Base ctor takes a parameter of the same name as one of the class' member variables:

class Base
{
protected:
  char *name;

public:
  Base(char ***name**)
  {
    cout << name << ": Base class cons" << endl;
  }

The ctor's parameter 'name' hides the class' member variable of the same, erm... name.

Second, you are slicing your object here:

int main()
{
  //Base b;
  //b.disp();
  Base c = Child("2");
  c.disp();
}

'c' is of type Base, and you are trying to assign a Child to it. All of the stuff that is unique to Child will be sliced off when you assign the ogbject to the base class.

Here is code that fixes both these problems:

#include <iostream>
#include <string>

using namespace std;

class Base
{
protected:
    std::string name_;

public:
  Base(char *name)
      : name_(name) {
    cout << name_ << ": Base class cons" << endl;
  }

  ~Base()
  {
    cout << name_ << ": Base class des" << endl;
  }

  virtual void disp();
};

void Base::disp()
{
  cout << name_ << ": Base disp()" << endl;
}

class Child : public Base
{
public:
  Child(char *name):
    Base(name)
  {
    cout << name_ << ": Child class cons" << endl;
  }

  ~Child()
  {
    cout << name_ << ": Child class des" << endl;
  }

  virtual void disp()
  {
    cout << name_ << ": Child disp()" << endl;
  }
};


int main()
{
  //Base b;
  //b.disp();
  Base * c = new Child("2");
  c->disp();
  delete c;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top