我有一种情况,我需要在没有 vtable 的情况下实现多态性。这就是我正在尝试做的事情
- 存在一个类层次结构:C 扩展 B,B 扩展 A
- 其思想是在 A 中声明一个函数指针,然后 B 和 C 的构造函数将其相应的方法分配给 A 中的函数指针
- 通过下面的代码,我能够实现 C 类的多态性,但不能实现 B 类的多态性。
显然我在这里遗漏了一些东西。我不确定这是否可能。非常感谢对此问题的任何见解。
我可以用下面的代码来做到这一点
A<C> *c = new C();
c->BasePrint(); //Reached C's Print
但不是这个
// A<B> *b = new B();
// b->BasePrint(); //Intentionally incorrect to demonstrate the problem.
有什么办法可以实现这一点吗?
template <typename T>
class A
{
public:
typedef void (T::*PrintFn)(void);
protected:
PrintFn printFn;
public:
void BasePrint()
{
if(printFn)
(((T*)this)->*printFn)();
}
};
template <typename T>
class B : public A<T>
{
public:
B()
{
printFn = &B::Print;
}
void Print()
{
//Print B
}
};
class C : public B<C>
{
public:
C()
{
printFn = &C::Print;
}
void Print()
{
//Print C
}
};
最佳答案
#include <iostream>
#include <typeinfo>
struct own_type {};
template<template<typename T>class CRTP, typename In, typename D>
struct DoCRTP: CRTP<In> {};
template<template<typename T>class CRTP, typename D>
struct DoCRTP<CRTP, own_type, D>: CRTP<D> {};
template<typename D>
struct A {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D*>(this); }
A() {
std::cout << "A<" << typeid(D).name() << ">\n";
self()->print();
}
};
template<typename T=own_type>
struct B:DoCRTP<A, T, B<T>> {
B() {
std::cout << "B<" << typeid(T).name() << ">\n";
}
void print() { std::cout<<"I am a B\n"; }
};
template<typename T=own_type>
struct C:DoCRTP<B, T, C<T>> {
C() {
std::cout << "C<" << typeid(T).name() << ">\n";
}
void print() { std::cout<<"I am a C\n"; }
};
void test() {
std::cout << "Instance of B<>:\n";
B<> b;
std::cout << "Instance of C<>:\n";
C<> c;
}
int main() {
test();
}
在这里,我们有一种方法可以传入最派生的类,如果您不传入任何内容,则假定您是最派生的类。
但是,您的设计存在问题 -- A
已经完全知道它的类型情况,所以不需要虚拟行为! BasePrint
可以static_cast<T*>(this)->Print()
这样你就可以省掉你的开销。
您遇到的根本问题是您在基类中存储特定类型的成员函数指针 A
.
无模板 A
可以存储指向非特定类型函数指针的指针——比如显式采用 A*
的“静态”函数指针作为第一个参数。在 C++11 中,您可以从成员函数自动构建这些函数。在 C++03 中,std::bind
应该让你将成员函数指针转换为 D
到需要 A*
的函数作为第一个参数。
关于c++ - C++中不带virtual的多态实现多级继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15575869/