我的代码遇到以下问题:
#include <iostream>
using namespace std;
class Base {
public:
virtual void sayHello()=0;
};
class Impl1 : public Base {
public:
void sayHello() { cout << "Hi from Impl1" << endl; }
};
class Impl2 : public Base {
public:
void sayHello() { cout << "Hi from Impl2" << endl; }
};
void sayHello(Impl1 *i) {
cout << "Impl1 says: ";
i->sayHello();
}
void sayHello(Impl2 *i) {
cout << "Impl2 says: ";
i->sayHello();
}
int main()
{
Impl1 *i1 = new Impl1();
Base *b = i1;
sayHello(b);
return 0;
}
这里编译器抱怨了sayHello(b);
行
码。
“调用重载'sayHello(Base *&amp;)'是模棱两可的”
有没有办法解决这个问题?
修改
我基本上想要将我的对象传递给一个根据对象类型进行一些计算的函数。我的对象故意缺乏信息以进行必要的计算。所以Impl1和Impl2只包含一些基本数据,不知道进行计算所需的更多数据。
答案 0 :(得分:3)
重载分辨率在编译时执行。这意味着对于sayHello(b);
,编译器只知道b
的类型是Base*
,它不会知道并且无法知道b
指向实际上是Impl1
个对象。然后导致模糊的呼叫;将Base*
转换为Impl1*
或Impl2*
是该呼叫的等效排名。
PS:可能是OT,但对于您的代码示例,使用Base*
的函数可以正常工作;动态调度将生效。
class Base {
public:
virtual void sayHello()=0;
};
class Impl1 : public Base {
public:
void sayHello() { cout << "Hi from Impl1" << endl; }
};
class Impl2 : public Base {
public:
void sayHello() { cout << "Hi from Impl2" << endl; }
};
void sayHello(Base *i) {
cout << "Some derived class of Base says: ";
i->sayHello();
}
int main()
{
Impl1 i1;
Impl2 i2;
Base *b = &i1;
sayHello(b); // "Hi from Impl1"
b = &i2;
sayHello(b); // "Hi from Impl2"
return 0;
}
如果您需要在运行时知道动态类型,可以使用dynamic_cast
。 e.g。
Base *b = /* something */;
Impl1 * pi1 = dynamic_cast<Impl1*>(b);
if (pi1 != nullptr) sayHello(pi1);
答案 1 :(得分:0)
由于在编译时解决了重载,因此必须为编译器提供确切的类型,以便重载解析成功。
为了分派类型,将虚拟成员函数添加到Base
,并使用它来选择重载:
class Base {
public:
virtual void sayHello()=0;
virtual void callSayHello() = 0;
};
class Impl1 : public Base {
public:
void sayHello() { cout << "Hi from Impl1" << endl; }
void callSayHello() {sayHello(this); }
};
class Impl2 : public Base {
public:
void sayHello() { cout << "Hi from Impl2" << endl; }
void callSayHello() {sayHello(this); }
};
void sayHello(Impl1 *i) {
cout << "Impl1 says: ";
i->sayHello();
}
void sayHello(Impl2 *i) {
cout << "Impl2 says: ";
i->sayHello();
}
...
b->callSayHello();
请注意callSayHello
的实现是相同的,但您不能将它们放入Base
类,因为this
的类型会有所不同。
注意:这个实现的想法来自Visitor Pattern的C ++实现。
答案 2 :(得分:0)
摆脱两个独立的功能并直接致电b->sayHello();
:
Impl1 *i1 = new Impl1();
Base *b = i1;
b->sayHello();
或者使用dynamic_cast
的简单解决方法:
Impl1 *i1 = new Impl1();
Base *b = i1;
sayHello(dynamic_cast<Impl1*>(b));
诉诸dynamic_cast
的需要经常表明课程设计中存在错误。这可能就是这种情况。有可能你永远不应该首先引入一个所谓的面向对象的基类。
另请注意,您最后不要致电delete
。如果这样做,您将需要Base
中的虚拟析构函数。