Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ inheritance with same function name

Sorry if this answer is already on this site, but I've looked all over and couldn't find any solutions to my issue. It pertains to same-name functions from inherited classes. Here is my code:

class A
{
public:
    int foo(int c) { c = c+1; return c; };
};

class B : public A
{
public:
    int foo(int c) { c = c-1; return c; };
};

int main()
{
    A array[2];
    array[0] = A item1;
    array[1] = B item2;
    for (int n=0;n<2;n++)
    {
        cout << array[n].foo(10) << endl;
    }
    return 0;
}

I would expect an output of:

11    // foo() from A class  [10 + 1 = 11]
9     // foo() from B class  [10 - 1 = 9 ]

But instead I get

11
11

From testing this out, I have found that the foo() function in the B class does not get called within the for-loop. Instead, the foo() function in the A class is called, even on the B object at array[1].

Is this because I have defined the array as containing objects of the A class only? If so, is there a way I can have the foo() function from the B class be called on the second object within that for-loop?

Thank you in advance for any help!

like image 763
ryantuck Avatar asked Dec 04 '12 20:12

ryantuck


People also ask

When a function with the same name appears in more than one base class in multiple inheritance?

Inheritance Ambiguity in C++ In multiple inheritances, when one class is derived from two or more base classes then there may be a possibility that the base classes have functions with the same name, and the derived class may not have functions with that name as those of its base classes.

Which is possible when a derived class function has the same name and signature as its base class?

Function overriding in C++ is a concept by which you can define a function of the same name and the same function signature (parameters and their data types) in both the base class and derived class with a different function definition.

Can C support multiple inheritance?

Master C and Embedded C Programming- Learn as you go So the class can inherit features from multiple base classes using multiple inheritance. This is an important feature of object oriented programming languages such as C++.

How do you call an inherited class function?

A derived class is created, which is inheriting parent class p1 and overloading the parent class function first(). class d1 : public p1 { public: void first() { cout << "The derived class d1 function is called."; p1::first(); } }; The function of d1 class is calling the function of p1 class.


3 Answers

I'll forget that array[0] = A item1; isn't valid C++ and just assume that you're assigning an object of type A to array[0] and an object of type B to array[1]. Okay, so you have two problems.

The first is known as object slicing. When you copy an object of type B to an object of type A, you only copy the A part of that object. So what you have in array[1] is not a B at all, it's just an A. If you want polymorphism (which you do), then you need to use either pointers or references which provide polymorphic behaviour. That means make your array an A* array[2]; and do array[0] = &item1; array[1] = &item2;.

Now, when you call a function on a pointer to A that points to a B it will still only call As foo member function. Why? Because by default, the function will be looked up on the static type of the object. That static type is A. If you want to tell the compiler to look up your function on the dynamic type of your object - the true type of your object, which is B - you need to make that member function virtual. So in A, do:

virtual int foo(int c) { c = c+1; return c; };

Now when your compiler see that you're calling foo on an A*, it'll see that it's virtual and say "Oh okay, I should look up this function dynamically" and it'll find B's implementation of foo.

like image 90
Joseph Mansfield Avatar answered Oct 17 '22 17:10

Joseph Mansfield


You are assigning your B instance to a space allocated for an A type. This leads to "slicing".

So first, you'd have to allow for other types via pointers or references. For example:

A* a = new B;
a->foo(10);

The other thing you must do is alert the compiler that foo() can be overridden. In C++, declare it as a virtual function:

virtual int foo(int c) { c = c+1; return c; };
like image 27
chrisaycock Avatar answered Oct 17 '22 16:10

chrisaycock


You are missing the virtual keyword.

 class A
 {
   virtual int foo(int c) { c = c+1; return c; };
 };

Also, to avoid slicing, instead of array of A use array of pointers to A:

A* array[2];
array[0] = new A;
array[1] = new B;
for (size_t i=0; i<2; ++i)
    cout << array[i]->foo(10) << endl;

or, better yet, make it a vector of pointers to A (std::vector<A*>).

Also, as a rule of thumb, destructor of your base class should be virtual too - it's not a problem for this particular example, but if derived classes add new members which they should release when destroyed, making the base class destructor virtual will make sure all the destructors in the hierarchy are called.

Another thing, this:

array[1] = B item2;

will not compile. If you declare the array as an array of pointers to A (or vector of pointers to A), you will be able to do:

array[1] = new B;
like image 4
piokuc Avatar answered Oct 17 '22 15:10

piokuc