在此示例中,我该怎么做才能触发正确的操作符:
#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;
}
输出为"class A"
,但应为"class B"
我怎么解决这个问题?感谢。
编辑:根据答案......我应该为每个派生类做这个:
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;
//...
}
答案 0 :(得分:2)
有两个原因:
B::operator/(B&)
不是A::operator/(A&)
的覆盖,因此在多态情况下永远不会被调用。B::operator/
将B&
作为参数,但*b
的静态类型为A
。答案 1 :(得分:1)
B::operator/
不是A::operator/
的覆盖,因为它们的参数不同。
如果签名兼容,则只能覆盖虚函数(或运算符)。
答案 2 :(得分:1)
您实际上并未覆盖operator/
中的A
,因为B::operator/
具有与A::operator/
不同的方法签名(参数类型为B&
} A&
)。因此,对operator/
类型的对象调用A&
会调用operator/
类的唯一现有A
,可能是virtual
,但不是覆盖class B
。因此,您需要做的是将operator/
的{{1}}更改为
B
请注意 void operator/(A& b){std::cout << "class B"<<std::endl;}
无论如何都不能用作*b
的参数,因为它的类型为B::operator/
而不是A&
类型。
答案 3 :(得分:1)
(首先,我将尝试解释目前正在发生的事情,但最后我会尝试写一个'正确的'程序。)
我将使用x
和y
代替a
和b
- 这有点不那么令人困惑。
A* x = new C;
A* y = new B;
*x / *y;
x
的静态类型是A
- 也就是变量的类型。 动态类型是变量指向的对象的实际类型,是C
。
y
的静态类型是A
- 也就是变量的类型。 动态类型是变量指向的对象的实际类型,是B
。
所以这里似乎涉及四种类型。但实际上,y
的动态类型永远不会相关,我们将会看到。所以留下(最多)三种相关类型。要理解这一点,让我们重写表达式如下:
x -> operator/ (*y);
首先,编译器查看x
的静态类型。在这种情况下,它是A
。然后它在具有适当签名的静态类型中查找方法。 “适当的签名”是什么意思?答案是方法查找忽略了动态类型的变量。 y
的静态类型为A,因此选择operator/(A&)
。 (我们知道y
实际上是B,但是被忽略了。)最后,运行时将查看动态类型x
(忽略y
)。动态类型为C
。由于A中的operator/(A&)
为virtual
,因此运行时实际上会调用C::operator/(A&)
。
简而言之,y
的动态类型无关紧要。永远不会调用方法operator/(B&)
或operator/(C&)
。应删除这些方法。
这里有一个基本的不对称。在*y / *x
中,y的动态类型是相关的,但不是动态类型的x。
在“解决”问题之前,我们需要确定我们知道问题是什么。因此,我将首先澄清我的解释。如果这是错误的解释,请提前道歉。
我将假设提问者打算x
的动态类型将始终与{{1>的动态类型相同如果它们不同,那么应该有一条错误消息。例如,此代码可以使用:
y
和
A * x = new A;
A * y = new A;
*x / *y; // divide an instance of A by another instance of A
和
A * x = new B;
A * y = new B;
*x / *y; // divide an instance of B by another instance of B
但不
A * x = new C;
A * y = new C;
*x / *y; // divide an instance of C by another instance of C
或
A * x = new B;
A * y = new C;
*x / *y; // should give an error
这是一个完整的程序:
A * x = new C;
A * y = new B;
*x / *y; // should give an error
B和C中的操作员做两件事:
#include <iostream>
#include <typeinfo>
#include <cassert>
using namespace std;
class A
{
public:
virtual void operator/(A& z) {
assert(typeid(z) == typeid(*this));
cout << "class A" << endl;
}
};
class B : public A
{
public:
virtual void operator/(A& z) {
assert(typeid(z) == typeid(*this));
cout << "class B" << endl;
B& b = dynamic_cast<B&>(z);
}
};
class C : public B
{
public:
virtual void operator/(A& z) {
assert(typeid(z) == typeid(*this));
cout << "class C" << endl;
C& c = dynamic_cast<C&>(z);
}
};
int main()
{
A* x = new C;
A* y = new C;
*x / *y;
}
的两侧都有相同的类型。/
转换为适当的类型,允许除法代码对两个操作数具有完全访问权限答案 4 :(得分:0)
使用静态类型解析编译时的运算符重载,并且只能处理A的一个重载(A类中的重载)(* b是编译器的A)