c++ - 在父容器中调用基于子容器的重载函数

标签 c++ c++14 overloading

我想将子对象存储在其父类型的容器中,然后根据容器中子对象的类型调用函数重载。这可能吗?

#include <vector>

class Parent { public: };

class A : public Parent { public: };
class B : public Parent { public: };
class C : public Parent { public: };

class Hander
{
public:
    static void handle(A & a) {}
    static void handle(B & b) {}
    static void handle(C & c) {}
};

int main()
{
    A test1;
    Hander::handle(test1); // compiles and calls the correct overload

    Parent test2 = A();
    Hander::handle(test2); // doesn't compile

    Parent * test3 = new A();
    Hander::handle(*test3); // doesn't compile

    Parent children1[] = { A(), B(), C() };
    for (int i = 0; i < 3; ++i)
        Hander::handle(children1[i]); // doesn't compile

    std::vector<Parent*> children2 = { new A(), new B(), new C() };

    for (int i = 0; i < 3; ++i)
        Hander::handle(*children2[i]); // doesn't compile
}

最佳答案

不,这是不可能的。

被调用的函数是在编译时选择的。假设您有这样的代码:

Base &o = getSomeObject();
handle(o);

编译器不知道 o 的真实类型。它只知道它是 Base 的某个子类型或 Base 本身。这意味着它将搜索接受类型为 Base 的对象的函数。

您可以自己实现类型检查或使用映射来存储可能的函数:

Base &o = getSomeObject();
functionMap[typeid(o)](o);

但是typeid仅当 Base 是一个多态类型 时才有效。这意味着它必须至少有一个虚函数。这将我们带到下一节:

但是你可以使用虚函数。

Virtual functions是可以被覆盖的类的非静态成员函数。正确的功能在运行时解析。以下代码将输出 Subt 而不是 Base:

class Base {
public: virtual std::string f() {return "Base"}
};
class Subt : public Base {
public: virtual std::string f() {return "Subt"}
};

int main() {
    Subt s;
    Base &b = s;
    std::cout << b.f() << std::endl;
}

Subt 的定义中可以省略virtual。函数 f() 已在其基类中定义为 virtual

具有至少一个虚函数(也称为多态类型)的类正在存储对虚函数表(也称为vtable)的引用).该表用于在运行时获取正确的函数。

你问题中的问题可以这样解决:

class Parent {
public:
    virtual void handle() = 0;
};

class A : public Parent {
public:
    void handle() override { /* do something for instances of A */ }
};
class B : public Parent {
public:
    void handle() override { /* do something for instances of B */ }
};
class C : public Parent {
public:
    void handle() override { /* do something for instances of C */ }
};

int main()
{
    std::vector<std::unique_ptr<Parent>> children = {
            std::make_unique<A>(),
            std::make_unique<B>(),
            std::make_unique<C>()};

    for (const auto &child : children)
        child->handle();
}

兼容性注意事项:关键字autooverride仅适用于 C++11 及更高版本。 range-based for loopstd::unique_ptr从 C++11 开始也可用。函数std::make_unique从 C++14 开始可用。但是虚函数也可以用于旧版本。

另一个提示:

多态性仅适用于引用和指针。以下将调用 Base::f() 而不是 Subt::f():

Subt s;
Base b = s;
std::cout << b.f() << std::endl;

在此示例中,b 将只包含一个类型为 Base 的对象,而不是 Subt。该对象刚刚在 Base b = s; 处创建。它可能会从 s 复制一些信息,但它不再是 s。它是 Base 类型的新对象。

关于c++ - 在父容器中调用基于子容器的重载函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35727280/

相关文章:

c++ - 接口(interface)的菱形继承(C++)

c++ - 通过 J2ME 代码卸载 J2ME 应用程序?

c++ - 接受类型对象和所有派生类型对象的模板函数

c++ - 如何实例化成员函数指针?

c++ - 有趣的问题运算符重载

c - 函数重载在 C 中有效吗?

c++ - #include c/c++中的绝对路径语法

c++ - 对于具有引用返回类型的搜索算法,默认返回值应该是什么?

c++ - C++ 模板声明中的范围和默认参数 : Clarifying Standardese

java - 为什么它总是给出调用整数参数方法而不是短参数方法