如何实现静态虚成员函数
How to implement static virtual member function
TL/DR:有没有(更方便的)方法来实现这样的功能?
我必须为类类型和类实例调用相同的静态代码,它们由对base的引用表示:
int main()
{
// Invokes on class
bar<C1>(); // invokes C1::foo()
bar<C2>(); // invokes C2::foo()
// Invokes on instance
bar(C1()); // invokes C1::foo()
bar(C2()); // invokes C2::foo()
}
但问题是,如果没有一些代码复制,我就无法实现它。对于每个派生类,我必须同时编写静态和虚拟方法。静态——因为我不能在类上调用虚方法,而虚方法调用静态——因为除了虚方法,没有办法区分对象的行为:
template<typename T>
void bar()
{
T::foo();
}
void bar(A const &r)
{
r.foo();
}
因此,我解决重复代码问题的方法是:
#include <iostream>
class A
{
public:
virtual void foo() const = 0;
};
template<typename derived_T>
class B: public A
{
public:
virtual void foo() const
{
derived_T::foo();
}
};
class C1 : public B<C1>
{
public:
static void foo()
{
std::cout << "C1::foo()" << std::endl;
}
};
class C2 : public B<C2>
{
public:
static void foo()
{
std::cout << "C2::foo()" << std::endl;
}
};
这种方法工作得很好,但是它至少有两个不便之处。
首先,我必须引入一个辅助模板类B,并实现虚方法。
其次,每个继承链(从B到final类)必须由模板组成,这使得不可能使用任何中间类作为指针/引用类型。如。A <- B <- T1 <- T2 <- C、T1和T2必须是模板类,以提供C::foo()。
一个可能的解决方案是使用基类注入的CRTP。
template <typename T, typename... Bases>
struct CRTPFooInjector : Bases...
{
virtual void vfoo() { T::foo(); }
};
这是你的注入器模板。它只实现了foo的虚版本,没有其他的。
struct Base: CRTPFooInjector<Base>
{
static int foo() { std::cout << "Base::foo()" << std::endl; }
};
struct Der1 : CRTPFooInjector<Der1, Base>
{
static int foo() { std::cout << "Der1::foo()" << std::endl; }
};
struct Der2 : CRTPFooInjector<Der2, Base>
{
static int foo() { std::cout << "Der2::foo()" << std::endl; }
};
struct Der12 : CRTPFooInjector<Der12, Der1, Der2>
{
static int foo() { std::cout << "Der12::foo()" << std::endl; }
};
现在你有一个稍微不同的Injector <- Base <- Injector <- Der1 <- Injector <- Der12
,而不是你正常的层次结构Base <- Der1 <- Der12
,但这对大多数用户来说应该是透明的。
如果你需要混合一些虚拟基类:
template <typename T>
struct Virtual : virtual T
{
};
struct Der1 : CRTPFooInjector<Der1, Virtual<Base>> ...
如果你有几个静态方法,你的派生类是固定的,你可以使用访问者模式:
class IAVisitor;
struct A
{
virtual ~A() = default;
virtual void accept(IAVisitor& visitor) = 0;
};
struct C1; struct C2; /*..*/; struct Cn;
struct IAVisitor
{
virtual ~IAVisitor() = default;
virtual visit(C1&) = 0;
virtual visit(C2&) = 0;
//...
virtual visit(Cn&) = 0;
};
struct C1 : A
{
void accept(IAVisitor& visitor) override {visitor.visit(*this);};
static void foo();
};
// Similar code for C2, Cn
template <typename F>
struct AVisitor_F : IAVisitor
{
AVisitor_F(F f) : f(f) {}
void visit(C1& a) override { f(a); }
void visit(C2& a) override { f(a); }
//...
void visit(Cn& a) override { f(a); }
F f;
};
和
struct FooCaller
{
template<typename T>
void operator () (const T&) const
{
T::foo();
}
};
最后:
AVisitor_F<FooCaller> fooVisitor;
a.accept(fooVisitor);
相关文章:
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 如何在C++中使用非静态成员函数作为回调函数
- (C++)为什么静态成员可以在初始化之前使用
- 类的全局对象和静态成员
- 在作为静态成员包含在另一个类中的类的构造函数中使用 cout
- 模板化类中静态成员的延迟初始化
- 使用静态成员声明类时遇到问题
- C++:是否可以使用非静态成员变量模板?
- 静态成员函数使用相同的名称时出现模板类型名称错误
- 如何在复杂继承中访问静态成员变量
- 在 nullptr 上调用无状态类的非静态成员函数是否合法?
- 如何在友元函数中使用静态成员而不添加前缀 [类名]::
- C++构造函数和静态成员
- 为什么传递非静态成员函数会导致编译错误?
- 非静态成员失败的线程调用函数
- 静态成员变量不会由 gettext 转换
- decltype:使用指针访问类的静态成员
- 处理类内的回调时,必须调用对非静态成员函数的引用
- 非静态成员函数的 decltype 格式不正确吗?
- 如何在C++中定义静态成员结构