在父容器中调用基于子容器的重载函数
Call overload function based on child in parent container
我想将子对象存储在其父类型的容器中,然后根据容器中子对象的类型调用函数重载。这可能吗?
#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 的 real 类型。它只知道它是 Base
或 Base
本身的某个子类型。这意味着它将搜索接受类型 Base
.
对象的函数
您可以自己实现类型检查或使用映射来存储可能的功能:
Base &o = getSomeObject();
functionMap[typeid(o)](o);
但是 typeid
仅在 Base
是 多态类型 时才会起作用。这意味着它必须至少有一个 虚函数 。这将我们带到下一节:
但是你可以使用虚函数。
Virtual functions 是 非静态 的 class 成员函数,可以被覆盖。正确的功能在运行时解析。以下代码将输出 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()
已在其基 class.
中定义为 virtual
类 具有至少一个虚函数(也称为 多态类型 )正在存储对 虚函数 table 的引用(也称为vtable)。这个table用于在运行时获取正确的函数。
你问题中的问题可以这样解决:
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();
}
兼容性注意事项: 关键字 auto
and override
are only available in C++11 and above. The range-based for loop and std::unique_ptr
is also available since C++11. The function 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
.
类型的新对象
我想将子对象存储在其父类型的容器中,然后根据容器中子对象的类型调用函数重载。这可能吗?
#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 的 real 类型。它只知道它是 Base
或 Base
本身的某个子类型。这意味着它将搜索接受类型 Base
.
您可以自己实现类型检查或使用映射来存储可能的功能:
Base &o = getSomeObject();
functionMap[typeid(o)](o);
但是 typeid
仅在 Base
是 多态类型 时才会起作用。这意味着它必须至少有一个 虚函数 。这将我们带到下一节:
但是你可以使用虚函数。
Virtual functions 是 非静态 的 class 成员函数,可以被覆盖。正确的功能在运行时解析。以下代码将输出 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()
已在其基 class.
类 具有至少一个虚函数(也称为 多态类型 )正在存储对 虚函数 table 的引用(也称为vtable)。这个table用于在运行时获取正确的函数。
你问题中的问题可以这样解决:
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();
}
兼容性注意事项: 关键字 auto
and override
are only available in C++11 and above. The range-based for loop and std::unique_ptr
is also available since C++11. The function 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
.