Question

I understand the basics of overloading and overriding- but something is confusing me. I will try to explain using a simple example:

  • Class B has a function X(B& b)
  • Class D inherits from Class B.
  • Class D overrides X with X(B& b) and also overloads it with X(D& d).

I then have the following code:

void test(D& d1, B& b1, D& d2, B& b2){
    d1.X(d2);
    d1.X(b2);
    b1.X(d2);
    b1.X(b2);
}

int main(){
    D d1, d2, d3, d4;
    test(d1, d2, d3, d4);
}

I am very unsure how the third and four lines of test() would determine which implementations of X() to call and what the general mechanisms are which are happening.

Was it helpful?

Solution 2

There are two steps involved: overload selection (X(B&) vs. X(D&)) and, once that is done, finding the right implementation of the selected function. The former happens at compile time and depends on the static types of the object and its arguments, the latter happens at run-time and depends on the dynamic type of the object (note it does not depend on the dynamic type of the arguments).

The four objects are declared as follows: d1 and d2 are D&, so their static type is D&, and b1 and b2 are declared as B&, so their static type is B&. The static type is what you've declared in the code.

But the dynamic type for all four is D, because all four references actually refer to objects that you've created as D-objects in main().

Therefore, first step, overload selection: In the case of b1.X(b2) and b1.X(d2), there is only one possible overload, X(B&), because the static type is B&, and the class definition for B has only this one function. But in the case of d1.X(b2) and d1.X(d2), the overload selection is based on the class definition of D, because the static type is D&. So two overloads are considered: X(B&) and X(D&). When the argument is b2, the former overload is chosen, and when the argument is d2, the latter overload is chosen – all based on the static (=declared) types of object and arguments.

Second step, chosing the right implementation of the selected overload. This happens at run-time and depends on the dynamic type of the object (not the arguments). So in the case of b1.X(b2), because the dynamic type of b1 is D, it will end up calling D::X(B&). Same for b1.X(d2): The overload selected in the previous step was X(B&), but the implementation chosen is D::X(B&). (D::X(D&) is no candidate at this point, because that would be a different overload, and the overload has been chosen based on the static type already). In the case of d1.X(b2) and d1.X(d2), the selected functions are the same as in the first step, D::X(B&) and D::X(D&), because the dynamic type of the object is the same as the static type.

OTHER TIPS

You declare a virtual function X in B(B::X), and override the X in the derived class D(D::X). If the parameter lists of B::X and D::X are different, B::X and D::X are considered different, D::X does not override B::X, and D::X is not virtual (unless you have declared it with the virtual keyword). Instead, D::X hides B::X.

#include <iostream>
using namespace std;

struct B {
   virtual void X() { cout << "Class B" << endl; }
};

struct D: B {
   void X(int) { cout << "Class D" << endl; }
};

int main() {
   D d;
   B* pb = &d;
//   d.X();
   pb->X();
}

You cannot even call d.X(), it is hidden by D::X(int). But pb->X() is fine.

So in your case:

struct B {
   virtual void X(B& b) { cout << "Class B" << endl; }
};

struct D: B {
   void X(B& b) { cout << "Class D" << endl; }
   void X(D& d) { cout << "Class D" << endl; }
};

The D::X will hide the B::X. So d1.X(d2) and d1.X(b2) in test() have nothing to do with B::X. And b1.X(d2), and b1.X(b2) in test() will call D::X. Although the B::X is invisible in D, but D::X(B&) is virtual, regardless of whether or not you declare D::X(B&) with the virtual keyword. The compiler knows it is a virtual function, so D::X(B&) gets called.

EDIT: More explaination on b1.X(b2), B::X is a virtual function, and D::X override it, so definitely it will call D::X by dynamic binding. And overloading is determined in compilation time, so it won't call D::X(D&).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top