0

Why the call of print() from pointer to base class (Class A) is working and call to print() from Child class object(Class C) is not working?

Statement 1: Will give "print A" as output as since A::print() is a virtual function it will call print() function of Class C which is inherited from A::print(). This will prove that Class C indeed has print() function

Statement 2: This will give compiler error as B::print(int x) will hide A::print().

Statement 3: Will give compilation error. Why?

Probably because print() is still hidden in Class C as Class C is also inheriting B::print(int x). If this is the case then why call from a->print() worked?

Another question: Is there any rule which specifies that B::print(int x) will hide A::print() in the child classes?

class A{
    public:
    virtual void print();
};

void A::print(){
    cout<<"print A\n";
}

class B:public A{
    public:
        void print(int x);
};

void B::print(int x){
    cout<<"print B " << x <<"\n";
}

class C:public B{
};

void funca(A *a){
    a->print();//Statement 1
}

void funcb(B *b){
    //b->print(); Statement 2
}

void funcc(C *c){
    //c->print(); Statement 3
}

int main(){

    C d;
    funca(&d);
    funcb(&d);
    funcc(&d);
}
Gtrex
  • 247
  • 1
  • 7
  • 1
    If you're happy that B is hiding print() then why would C be any different? – UKMonkey Jan 07 '19 at 10:27
  • @UKMonkey, since A::print() is virtual,won't it call C::print() because of dynamic binding? – Gtrex Jan 07 '19 at 15:49
  • C isn't an A; it's a B (which happens to be an A) but B has already hidden print. – UKMonkey Jan 07 '19 at 16:03
  • @UKMonkey Please correct me if I am wrong. when `a->print()` is called code will check if `A::print()` is virtual or not. Since `A::print()` is virtual it will start searching for the first definition of print() from the bottom of inheritance tree. Since both `Class C` and `Class B` does not have it that is why `A::print()` is executed. – Gtrex Jan 07 '19 at 17:37
  • You're wrong :) your example lists #3 as getting passed a C; not an A; so for #3, the compiler will attempt to find C::print; then B::print - and on locating B::print(x); it will fail to find A::print() for the exact same reason if failed to find it in example #2. B has hidden it not only for itself, but all classes that inherit it... unless they unhide it explicitly. – UKMonkey Jan 07 '19 at 17:43
  • @UKMonkey, previous comment I was talking about Statement1 – Gtrex Jan 07 '19 at 17:50
  • In that case correct enough - `print()` and `print(int x)` are different functions; and only A implements a print() – UKMonkey Jan 07 '19 at 17:52
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/186317/discussion-between-gtrex-and-ukmonkey). – Gtrex Jan 07 '19 at 18:01

2 Answers2

3

Probably because print() is still hidden in Class C as Class C is also inheriting B::print(int x). If this is the case then why call from a->print() worked?

A is base class so there is nothing to hide there, a->print() just works from base class context.

Both B and C hides the original print() function with a different prototype print(int) and so the error as the function is called with wrong prototype (there is no more print() in B or C class)

artm
  • 17,291
  • 6
  • 38
  • 54
  • will the call to `a->print()` not call `c->print()` since `A::print()` is virtual ? – Gtrex Jan 07 '19 at 15:44
  • No, because `a` is pointer to base class `A`, not a pointer to derived class `C` – artm Jan 07 '19 at 16:13
  • you mentioned "there is no more print() in B or C class".... arn't they still there but hidden. Because when we call `a->print()` in Statement 1 since `A::print()` is virtual it will start searching for the first definition of `print()` from the bottom of inheritance tree. Since both `Class C` and `Class B` does not have any definition of their own but they are inheriting `print()` (but hidden) that is why `A::print()` is executed – Gtrex Jan 07 '19 at 17:59
1

Statement 3: Will give compilation error. Why?

For the same reason that b->print() didn't work. This is the error when Statement 2 runs:

In function 'void funcb(B*)':
error: no matching function for call to 'B::print()'
     b->print(); //  Statement 2
              ^
note: candidate: 'void B::print(int)'
 void B::print(int x){
      ^
note:   candidate expects 1 argument, 0 provided

This is the error when Statement 3 runs:

In function 'void funcc(C*)':
error: no matching function for call to 'C::print()'
     c->print(); //  Statement 3
              ^
note: candidate: 'void B::print(int)'
 void B::print(int x){
      ^
note:   candidate expects 1 argument, 0 provided

It's practically the same error, since as you've guessed: C inherits B, whose print function hides A's.

If this is the case then why call from a->print() worked?

Because your reference to C was casted into a pointer to A, as such, exposing A's print function instead of B's. If you do this explicitly, you'd get the same results:

static_cast<A*>(&d)->print();    //  print A
static_cast<B*>(&d)->print();    //  error: no matching function for call to 'B::print()'
TrebledJ
  • 8,713
  • 7
  • 26
  • 48
  • 1
    `B`'s `print()` function hides `A`'s - it doesn't override it. – Peter Jan 07 '19 at 10:40
  • @Peter Ah ok, thanks. But would it be correct to say that `B`'s `print()` function overrides `A` if the arguments to `print` were the same in both A and B? – TrebledJ Jan 07 '19 at 10:43
  • @TrebuchetMS Not really, since you could call `A::print(...)` from `B::print(...)`. – Benjamin Barrois Jan 07 '19 at 10:51
  • 1
    Only if the method was virtual, which would be why `override` exists. – Matthieu Brucher Jan 07 '19 at 10:51
  • @TrebuchetMS, you have mentioned that reference to C is casted into A but A::print() is virtual so will it not call C::print() according to dynamic binding? – Gtrex Jan 07 '19 at 15:40
  • `A::print()` and `C::print(int)` are two different print functions, so apparently no binding occurs. If you try your example with `B::print()` instead of `B::print(int)` and uncomment all three of your Statements, you'd see that indeed, all three print `print B`. – TrebledJ Jan 07 '19 at 16:06
  • @TrebuchetMS, so it means Both C::print(int x) and C::print() are hidden and C::print(int x) is given higher priority ? OR since B::print(int x) hides B::print() in class B it will not inherited by Class C? – Gtrex Jan 07 '19 at 17:29
  • @Gtrex You can't call `C::print()` or `C::print(int)` from an instance or pointer to `A` (the base class) unless you first do a `dynamic_cast` (or something similar along those lines). If you try to call `C::print()` with a pointer to `A`, you'd get the error: `error: 'C' is not a base of 'A'`. – TrebledJ Jan 08 '19 at 02:06