简体   繁体   English

基于派生类的C ++重载方法

[英]C++ overloading method based on derived class

I am facing the following problem with my code: 我的代码遇到以下问题:

#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;
}

And here the compiler complains about the sayHello(b); 在这里,编译器抱怨sayHello(b); line in the code. 代码中的一行。

"call of overloaded 'sayHello(Base*&)' is ambiguous" “调用超载'sayHello(Base *&)'含糊不清”

Is there a way to solve this problem? 有没有办法解决这个问题?

EDIT: 编辑:

I basically want to pass my object to a function that does some calculations based on the type of the object. 我基本上想要将我的对象传递给一个函数,该函数根据对象的类型进行一些计算。 My object intentionally lacks of information in order to make the needed calculations. 我的对象故意缺乏信息以进行必要的计算。 So Impl1 and Impl2 just contain some basic data, without the knowledge of more data needed to do the calculations. 所以Impl1和Impl2只包含一些基本数据,而不知道进行计算所需的更多数据。

Overload resolution is performed at compile time. 过载分辨率在编译时执行。 It means for sayHello(b); 对于sayHello(b);意味着它sayHello(b); , the compiler only know that the type of b is Base* , it won't and can't know that b is pointing to a Impl1 object actually. ,编译器只知道b的类型是Base* ,它不会也不会知道b实际上是指向一个Impl1对象。 Then results in ambiguous call; 然后导致模糊的呼叫; converting Base* to Impl1* or Impl2* is equivalent rank for the call. Base*转换为Impl1*Impl2*是等效的呼叫等级。

PS: might be OT, but for you code sample, a function taking a Base* would work fine; PS:可能是OT,但对于你的代码示例,一个以Base*Base*的函数可以正常工作; dynamic dispach will take effect. 动态调度将生效。

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;
}

If you need to know the dynamic type at run-time, you can use dynamic_cast . 如果您需要在运行时知道动态类型,可以使用dynamic_cast eg 例如

Base *b = /* something */;
Impl1 * pi1 = dynamic_cast<Impl1*>(b);
if (pi1 != nullptr) sayHello(pi1);

Since overloads are resolved at compile time, you have to supply the compiler with the exact type in order for the overload resolution to succeed. 由于在编译时解决了重载,因此必须为编译器提供确切的类型,以便重载成功。

In order to dispatch on the type, add a virtual member function to the Base , and use it to choose the overload: 为了在类型上调度,将一个虚拟成员函数添加到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();

Note that implementations of callSayHello are identical, but you cannot place them into Base class, because the type of this would be different. 请注意,实现callSayHello是相同的,但你不能把它们放入Base类,因为类型this将是不同的。

Note: the idea for this implementation is borrowed from C++ implementation of the Visitor Pattern . 注意:此实现的想法来自访问者模式的 C ++实现。

Get rid of the two free-standing functions and call b->sayHello(); 摆脱两个独立的功能并调用b->sayHello(); directly: 直:

Impl1 *i1 = new Impl1();
Base *b = i1;
b->sayHello();

Or use an ugly workaround with dynamic_cast : 或者使用dynamic_cast的丑陋变通方法:

Impl1 *i1 = new Impl1();
Base *b = i1;
sayHello(dynamic_cast<Impl1*>(b));

The need to resort to dynamic_cast often suggests an error in the class design. 采用dynamic_cast的需要通常表明类设计中存在错误。 This may very well be the case here. 这可能就是这种情况。 Chances are that you should never have introduced a supposedly object-oriented base class in the first place. 有可能你永远不应该首先引入一个所谓的面向对象的基类。


Note also that you do not call delete at the end. 另请注意,您最后不要调用delete If you do, you will need a virtual destructor in Base . 如果这样做,您将需要Base的虚拟析构函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM