1
class A {
public:
    A() { foo(); }
    ~A() { foo(); }
    void foo() { cout << 3; }
    void bar() { foo(); }
};
class B : public A {
    void foo() { cout << 2; }
};
int main() {
    B b;
    b.bar();
    return 0 ;
}

I compiled and ran it . The result is 333 ... but I thought: when I call b.bar() . It would be directly to bar() and then call foo() function which is in class B because foo() in class A is overridden in class B . The result I thought is 323 . But I was wrong. Have I missed something ? Please help me to explain how it atually works @

Christophe
  • 68,716
  • 7
  • 72
  • 138
Ya Zawsze
  • 337
  • 2
  • 5
  • 7
    I think you wanted a `virtual foo()` – UKMonkey Jan 08 '18 at 18:11
  • My two cents here: 1) even if you implement foo() as a virtual function, once called in "A" constructor it will run A::foo() instead of B::foo() because there is no "B" created yet; 2) you MUST NOT call any virtual function in destructors because "B" can be destroyed already and dereferencing B::foo() pointer can crash the app, or deal with the already-overwritten memory, or something else. And here we don't talk about virtual inheritance yet, it would make the things way more tricky. – Yury Schkatula Jan 08 '18 at 19:06

3 Answers3

3

THe problem is that you have a non virtual foo() so that A::bar() will call the only foo() it knows, being A::foo(), even if it's B that invokes it.

Try:

class A {
public:
    A() { foo(); }
    virtual ~A() { foo(); }             // <<---------- recommendation
    virtual void foo() { cout << 3; }   // <<<--------- solves it
    void bar() { foo(); }
};
class B : public A {
    void foo() override { cout << 2; }  // <<---------- recommendation
};

Additional infos:

Making foo() virtual in the base class allows each class to override this function, and be sure that the foo() that is invoked is will be the foo() corresponding to the object's real class.

It's a good practice then to use the keyword override in the derived classes: it's not mandatory, but in case you make a typo in the functions signature, you'll immediately notice with a compile-time error message.

Another good practice is to make your base class destructor virtual if you have at least one virtual function in the class.

A final remark: in B, foo()'s private. This is legal, but it's weird because the inheritance says that B is a kind of A, but you can't use B objects exactly as an A object.

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

Member A::foo is non-virtual and will therefore be statically bound wherever used. So when compiling A::bar, the call to foo() will be (statically) bound to the implementation A::foo(). This statical binding in A::foo will not be changed by the fact that you create an instance of derived class B later on. If you call b.foo() in you main, however, B::foo will be bound.

In order to have B::foo to be called through A::bar, you'll have to declare A::foo as `virtual:

class A {
public:
    A() { foo(); }
    virtual ~A() { foo(); }
    virtual void foo() { cout << 3; }
    void bar() { foo(); }
};

Note that you'd also declare the destructor as virtual; non-virtual destructors do very rarely make sense.

Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
-1

You must include virtual in order to override the functionality stored in A.

Add to A

virtual void foo() { cout << 3; } 

and to B

void foo() override { cout << 2; }

Should do the trick. Virtual functions are member functions whose behavior can be overridden in derived classes. As opposed to non-virtual functions, the overridden behavior is preserved even if there is no compile-time information about the actual type of the class. If a derived class is handled using pointer or reference to the base class, a call to an overridden virtual function would invoke the behavior defined in the derived class.

Evan Gertis
  • 1,796
  • 2
  • 25
  • 59