Why do I get a segmentation fault when calling a virtual method in this code?

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!

By : Srikanth


Answers

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.

By : bayda


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


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.



This video can help you solving your question :)
By: admin