-3

I have some doubts about subclasses in C++. I have this code:

class BaseClass() {
    BaseClass();
    void doSomething();
}

class SubClass : public BaseClass {
    SubClass();
    void doSomething();
}

When I declare a BaseClass object that could be a SubClass I do it calling the sub constructor...

BaseClass foo = SubClass();

Then I need foo to use the doSomething() method of the derived class, but when I do it this way...

foo.doSomething();

It uses the parent class method instead of the derived one. I tried this, but it doesn't work:

foo.SubClass::doSomething();

Is there any way to do it or I'm forced to declare the object with "SubClass" type to make it use its own function?

Christophe
  • 68,716
  • 7
  • 72
  • 138
JotaEle
  • 154
  • 8
  • 1
    `virtual void doSomething();`?? – πάντα ῥεῖ Nov 26 '16 at 18:27
  • 3
    `BaseClass foo = SubClass();` -- `foo` is an object of type `BaseClass`, not `SubClass`. This is an example of **object slicing**. And marking `doSomething()` virtual would not change this. – Pete Becker Nov 26 '16 at 18:29
  • Yes, as Pete Becker said it seems an object slicing problem, so making the function virtual doesn't solve the problem... The only way to solve this is to explicitly declare foo as SubClass type, isn't it? – JotaEle Nov 26 '16 at 19:08

3 Answers3

2

Use virtual and override:

class BaseClass() {
    BaseClass();
    virtual ~BaseClass() = default;
    virtual void doSomething();
}

class SubClass : public BaseClass {
    SubClass();
    void doSomething() override ;
}

edit: as Christophe said, use a virtual destructor as above.

Johan Lundberg
  • 26,184
  • 12
  • 71
  • 97
2

Problem 1: object slicing

In your initialization

BaseClass foo = SubClass();

you create an anonymous temporary SubClass object and copy-construct a BaseClass object. This means that foo is and remains a BaseClass that is copied from a SubClass.

This is called object slicing. If the baseClass would have data members, the corresponding data members of the subclass would be copied into it. If SubClass would have additional data members, these would be lost.

If you want to work with BaseClass objects, but without loosing the members of their real type, whether base or derived, you need to use reference or pointers:

BaseClass *foo = new SubClass;  // foo is a base class pointer but points to a SubClass object. 

SubClass bar;  
BaseClass& foo2 = bar;          // foo2 is a base class REFERENCE which refers to a Subclass object

But, this is not sufficient.

Problem 2: polymorphism

If you'd now calling the method:

foo->doSomething();  
foo2.doSomething(); 

it would still be BaseClass::doSomething() that would be called, despite the real type of the object pointed/referred to. That's because for normal member functions, the compiler tries to identify the function to call at compile time: and at compile it only knows the type of the pointer or reference.

To benefit from a polymorphic behavior, you also need to define the function as virtual as explained by Johan. In this case, the compiler would generate code that with a little overhead is able to identify dynamically the type of the object and hence would call the correct version of the function exactly as you expect.

Note that if you have at least one virtual function in your base class, you'd better declare a virtual destructor for it.

Community
  • 1
  • 1
Christophe
  • 68,716
  • 7
  • 72
  • 138
0

You can declare the dosomeThing method virtual in BaseClass, like

virtual void doSomething()
{
   ----
}
Bo Persson
  • 90,663
  • 31
  • 146
  • 203
Muhammad Ramzan
  • 294
  • 6
  • 14