Ada*_*dam 6 c++ polymorphism operator-overloading non-member-functions object-slicing
背景资料
我已经用Java编程了一段时间,而且我几个月前才切换到C++,所以如果答案只是我错过的傻话,我会道歉!现在已经说过了,现在是时候解决问题吧!我正在开发一个基于文本的基本游戏引擎,最近我遇到了一个有趣的具体且不太可能的问题.我尝试在下面的程序中以较小的比例测试它,并决定只显示(而不是我的实际游戏代码),以免屏蔽屏幕,并使问题更少复杂.下面建模的问题反映了我的实际代码的问题,只是没有蓬松的干扰者.
问题
本质上问题是多态性之一.我想重载输出操作符"<<"以作为显示功能,该功能对于层次结构中的每个对象都是唯一的.问题是,当我从存储这些层次结构成员的列表中调用此运算符时,它们将丢失其标识并调用基类的输出运算符.通常,人们可以通过使用简单的显示方法替换运算符重载,将显示方法标记为虚拟,并继续他们快乐的一天来解决这个问题.我并不特别介意对代码进行更改,但现在我只是好奇.有没有办法在层次结构中重载运算符,导致我在这里得到什么?
[示例]代码
#include <vector>
#include <iostream>
#include <string>
using namespace std;
class Polygon {
friend ostream& operator<<(ostream& os, const Polygon& p);
public:
private:
};
class Rectangle : public Polygon {
friend ostream& operator<<(ostream& os, const Rectangle& r);
public:
private:
};
class Square : public Rectangle {
friend ostream& operator<<(ostream& os, const Square& s);
public:
private:
};
ostream& operator<<(ostream& os, const Polygon& p) {
os << "Polygon!" << endl;
return os;
}
ostream& operator<<(ostream& os, const Rectangle& r) {
os << "Rectangle!" << endl;
return os;
}
ostream& operator<<(ostream& os, const Square& s) {
os << "Square!" << endl;
return os;
}
int main() {
vector<Polygon*> listOfPoly;
listOfPoly.push_back(new Polygon());
listOfPoly.push_back(new Rectangle());
listOfPoly.push_back(new Square());
for(Polygon* p : listOfPoly) {
cout << *p;
}
}
Run Code Online (Sandbox Code Playgroud)
[示例]代码的输出
Polygon!
Polygon!
Polygon!
Run Code Online (Sandbox Code Playgroud)
[示例]代码的期望输出
Polygon!
Rectangle!
Square!
Run Code Online (Sandbox Code Playgroud)
有没有办法在层次结构中重载运算符,导致我在这里得到什么?
没有.
问题是,运营商都没有在您的层次结构.friend这里的关键字只是向前声明一个自由函数,并赋予它对该类的特权访问权限.它不是一个方法,所以它不能是虚拟的.
请注意,运算符重载只是语法糖.表达方式
os << shape;
Run Code Online (Sandbox Code Playgroud)
可以解析为自由功能(就像你在这里)
ostream& operator<< (ostream&, Polygon&);
Run Code Online (Sandbox Code Playgroud)
或者是左手操作数的成员,例如
ostream& ostream::operator<<(Polygon&);
Run Code Online (Sandbox Code Playgroud)
(显然这里第二种情况不存在,因为你必须修改std::ostream).语法无法解析的是右侧操作数的成员.
因此,您可以拥有一个自由函数运算符(必须是非虚拟的),或左手操作数上的方法(可能是虚拟的),但不是右操作数上的方法.
通常的解决方案是为层次结构的顶层提供单个重载,该重载将分派给虚拟方法.所以:
class Polygon {
public:
virtual ostream& format(ostream&);
};
ostream& operator<<(ostream& os, const Polygon& p) {
return p.format(os);
}
Run Code Online (Sandbox Code Playgroud)
现在只需实现Polygon::format,并在派生类中覆盖它.
另外,friend无论如何使用都带有代码味道.一般来说,为您的类提供足够完整的公共接口以使外部代码不需要特权访问来使用它,这被认为是更好的样式.
进一步深入了解背景信息:多重调度是一件事,当所有参数类型都是静态已知时,C++重载决策可以很好地处理它.未处理的是在运行时发现每个参数的动态类型,然后尝试找到最佳重载(如果考虑多个类层次结构,则显然是非平凡的).
如果你有一个编译时多态的元组替换运行时多态性的列表,并遍历是,你原来的重载方案将正确地调度.
| 归档时间: |
|
| 查看次数: |
596 次 |
| 最近记录: |