What shall I do in this example to trigger the right operator:
#include<iostream>
using namespace std;
class A
{
public:
virtual void operator/(A& a){cout << "class A";}
};
class B : public A
{
public:
void operator/(B& b){cout << "class B";}
};
int main()
{
A* a = new B;
A* b = new B;
*a / *b;
return 0;
}
The output is "class A" but it should be "class B".
How can I solve this? Thanks.
EDIT: According to answers… should I do this for every derived class:
class A
{
public:
virtual void operator/(A& a){cout << "class A";}
};
class B : public A
{
public:
virtual void operator/(A& a) override {cout << "class B";}
};
class C : public B
{
public:
virtual void operator/(A& a) override {cout << "class C";}
};
class D: public C
{
public:
void operator/(A& a) override {cout << "class D";}
};
int main()
{
A* a = new D;
A* b = new D;
*a / *b;
//...
}
(First, I’m going to try to explain what’s happening at the moment, but at the end I’ll try to write a ‘correct’ program.)
I’m going to use
xandyinstead ofaandb– it’s bit less confusing.The static type of
xisA– i.e. that’s what the type of the variable is. The dynamic type, the real type of the object pointed at by the variable, isC.The static type of
yisA– i.e. that’s what the type of the variable is. The dynamic type, the real type of the object pointed at by the variable, isB.So there are four types that seem to be involved here. But actually, the dynamic type of
yis never relevant, as we will see. So that leaves (at most) three relevant types. To understand this, let’s rewrite the expression as follows:First, the compiler looks at the static type of
x. In this case it isA. Then it looks for a method in the static type with the appropriate signature. What does ‘appropriate signature’ mean? The answer is that method lookup ignores the dynamic type of variables. The static type ofyis A, and henceoperator/(A&)is selected. (We knowyis really a B, but that’s ignored. )Finally, the runtime will look at the dynamic type ofx(ignoringy). The dynamic type isC. Because theoperator/(A&)wasvirtualin A, then the runtime will actually call theC::operator/(A&)instead.In short, the dynamic type of
yis not relevant. The methodsoperator/(B&)oroperator/(C&)will never be called. Those methods should be deleted.There’s a fundamental asymmetry here. In
*y / *x, the dynamic type of y would be relevant, but not the dynamic type of x.How to fix it
Before ‘fixing’ the problem, we need to be sure we know what the question is. Hence, I’ll clarify my interpretation first. If this is the wrong interpretation, apologies in advance.
I’m going to assume that the questioner intends that the dynamic type of
xwill always be the same as the dynamic type ofy, and that if they are different then there should be an error message. For example, this code is expected to work:and
and
but not
or
Here is a complete program that does this:
The operators in B and C do two things:
/have the same type.A&to the appropriate type, allowing the division code to have full access to both operands