派生类调用带有特定参数的基类方法

问题描述 投票:0回答:2

考虑以下代码:

#include <iostream>

struct Thing {
    void foo(bool b = true) {
        std::cout << "Thing::foo() called with b = " << std::boolalpha << b << ".\n";
    }
};

struct Blob : Thing { };

struct Event {
    void execute(Thing& thing) { thing.foo(); }
};

int main() {
    Blob blob;
    Event event;
    event.execute(blob);
}

输出:

Thing::foo() called with b = true.

假设我们想要输出:

Thing::foo() called with b = false.

Thing
Blob
类型(以及此处未提及的
Thing
的许多其他派生类)时,但仅当从
Event
调用时,以及从
Event
派生的任何类。

过载解决方案:

struct Event {
    void execute(Thing& thing) { thing.foo(); }
    void execute(Blob& blob) { blob.foo(false); }
};

不是理想的解决方案,因为

Thing
的许多其他派生类需要此类重载(并且此类派生类的列表将随着程序的发展而不断增加 所以模板元编程解决方案也不会是理想的)。

我想到的一个方案是引入虚方法:

struct Thing {
    void foo(bool b = true) {
        std::cout << "Thing::foo() called with b = " << std::boolalpha << b << ".\n";
    }
    virtual void fooDuringEvent(bool b = true) { foo(b); }
};

struct Blob : Thing {
    void fooDuringEvent(bool = true) override { foo(false); }
};

struct Event {
    void execute(Thing& thing) { thing.fooDuringEvent(); }
};

这行得通,但是很容易在需要的时候错误地调用

foo()
而不是
fooDuringEvent()
,例如

struct Task : Event {
    void execute(Thing& thing) {
        // Stuff
        thing.foo();  // Oops!
        // Other stuff
    }
};

那么处理这个问题的最佳解决方案是什么?

c++ overloading virtual
2个回答
1
投票

如果你需要

Thing
根据调用者的不同表现不同,那么你需要告诉它调用者是谁。

struct Thing {
    enum {CALLER_NOT_EVENT, CALLER_IS_EVENT} Caller;

    void foo(Caller callerIsEvent, bool b = (bool)callerIsEvent) {
        std::cout << "Thing::foo() called with b = " << std::boolalpha << b << ".\n";
    }
};

struct Blob : Thing { };

struct Event {
    void execute(Thing& thing) { thing.foo(CALLER_IS_EVENT); }
};

您也可以使用模板或

typeid
玩游戏,但在我看来,显式枚举更简洁、更容易。


0
投票

利用 Mooing Duck 的想法,我想出了这样的东西:

#include <iostream>

struct Event;

struct Thing {
    template <typename T> void foo (T& t, bool b = true) { fooBasic(b); }
    virtual void foo(Event&, bool b = true) { fooBasic(b); }
private:
    virtual void fooBasic(bool b = true) {  // Cannot be called from Event.
        std::cout << "Thing::fooBasic() called with b = " << std::boolalpha << b << ".\n";
    }
};

struct Blob : Thing {
    void foo(Event&, bool = true) override { fooBasic(false); }
    void fooBasic(bool b = true) override {
        std::cout << "Blob::fooBasic() called with b = " << std::boolalpha << b << ".\n";
    }
};

struct Event {
    void execute(Thing& thing) { thing.foo(*this); }  // 'thing.foo();' will not compile.
};

int main() {
    Blob blob;
    Event event;
    event.execute(blob);
}
© www.soinside.com 2019 - 2024. All rights reserved.