模拟虚拟方法的构造函数
Simulate constructor behaviour for virtual methods
我目前正在使用C 进行一个小型私人项目,我提出了以下结构:
#include <iostream>
class A
{
std::vector<int> vec;
protected:
virtual bool onAdd(int toAdd) {
// should the 'adding' be suppressed?
// do some A specific checks
std::cout << "A::onAdd()" << std::endl;
return false;
}
public:
void add(int i) {
if(!onAdd(i)) {
// actual logic
vec.push_back(i);
}
}
};
class B : public A
{
protected:
bool onAdd(int toAdd) override {
// do some B specific checks
std::cout << "B::onAdd()" << std::endl;
return false;
}
};
在此示例中,onAdd
基本上是为add
的回调,但以更多态的方式。
当C
类从B
继承并希望覆盖onAdd
时,实际问题就会出现。在这种情况下,在调用C::add
时,B中的实现将被丢弃(即未调用)。因此,基本上我想实现的是一种类似构造函数的行为,我能够在类层次结构中的不同位置覆盖相同的方法,所有这些方法都被称为。
我现在的问题是:实现这一目标有可能/设计吗?我相信它不会像级联构造函数那样容易。
NOTE :不要过多地关注add
示例。问题是关于回调的结构,而不是使用add
是否有意义。
我只会叫我的父母onadd()
bool C::onAdd(int toAdd) {return my_answer && B::onAdd(toAdd);}
,如果您期望其他开发人员从基类继承,这可能会有些困惑。但是对于小型私人层次结构,它可以很好地工作。
我有时包括一个使用语句,以使其更加明确
class C : public B
{
using parent=B;
bool onAdd(int toAdd) override {return my_answer && parent::onAdd(toAdd);}
};
struct RunAndDiscard {
template<class Sig, class...Args>
void operator()(Sig*const* start, Sig*const* finish, Args&&...args)const{
if (start==finish) return;
for (auto* i = start; i != (finish-1); ++i) {
(*i)(args...);
}
(*(finish-1))(std::forward<Args>(args)...);
}
};
template<class Sig, class Combine=RunAndDiscard>
struct invokers {
std::vector<Sig*> targets;
template<class...Args>
decltype(auto) operator()(Args&&...args)const {
return Combine{}( targets.data(), targets.data()+targets.size(), std::forward<Args>(args)... );
}
};
struct AndTogetherResultWithShortCircuit {
template<class Sig, class...Args>
bool operator()(Sig*const* start, Sig*const* finish, Args&&...args)const{
if (start==finish) return true;
for (auto* i = start; i != (finish-1); ++i) {
if (!(*i)(args...)) return false;
}
return (*(finish-1))(std::forward<Args>(args)...);
}
};
这将创建一个每件事表,要做onAdd
。
创建每级表更难;您需要使用父母类型的表格链接,这需要每类样板。
没有办法让C 编译器编写每种现代版本或每级版本,而无需自己操作。
有20个提案,涉及反射和重新化,以及掌层提案,可能涉及这样的写作代码(以每种结构和每类为基础)。
这是该技术正在测试的现场示例:
struct AndTogetherResultWithShortCircuit {
template<class Sig, class...Args>
bool operator()(Sig*const* start, Sig*const* finish, Args&&...args)const{
if (start==finish) return true;
for (auto* i = start; i != (finish-1); ++i) {
if (!(*i)(args...)) return false;
}
return (*(finish-1))(std::forward<Args>(args)...);
}
};
class A {
std::vector<int> vec;
protected:
invokers<bool(A*, int), AndTogetherResultWithShortCircuit> onAdd;
public:
void add(int i) {
if (!onAdd(this, i)) {
vec.push_back(i);
}
}
};
class B : public A
{
public:
B() {
onAdd.targets.push_back([](A* self, int x)->bool{
// do some B specific checks
std::cout << "B::onAdd(" << x << ")" << std::endl;
return x%2;
});
}
};
class C : public B
{
public:
C() {
onAdd.targets.push_back([](A* self, int x)->bool{
// do some B specific checks
std::cout << "C::onAdd(" << x << ")" << std::endl;
return false;
});
}
};
当您想编写自己的OO系统时,可以在C 中,但是C 不为您编写。
如果您想要一个通用解决方案,也许可以将CRTP与variadic模板一起使用,而不是运行时多聚生物学。
从这个答案中汲取灵感和此答案:
template<class... OnAdders> class A : private OnAdders... {
std::vector<int> vec;
template<class OnAdder>
bool onAdd(int toAdd){
return static_cast<OnAdder*>(this)->onAdd(toAdd);
}
template<typename FirstOnAdder, typename SecondOnAdder, class... RestOnAdders>
bool onAdd(int toAdd){
if (onAdd<FirstOnAdder>(toAdd))
return true;
return onAdd<SecondOnAdder, RestOnAdders...>(toAdd);
}
public:
void add(int i) {
if (onAdd<OnAdders...>(i))
return;
// actual logic
vec.push_back(i);
}
};
class B {
public:
bool onAdd(int toAdd) {
// do some B specific checks
std::cout << "B::onAdd()" << std::endl;
return false;
}
};
您可以使用:
A<B,C> a;
a.add(42);
实时演示。
以下解决方案使用std::function
在每个构造函数期间添加每个回调:
#include <iostream>
#include <vector>
#include <functional>
class A
{
std::vector<int> vec;
protected:
bool onAdd(int toAdd)
{
// do some A specific checks
std::cout << "A::onAdd()" << std::endl;
return true;
}
// vector of callback functions. Initialized with A::onAdd() callback as the first entry
std::vector<std::function<bool(int)>> callbacks{{[this](int toAdd){return onAdd(toAdd); }}};
public:
void add(int i)
{
for(auto& callback : callbacks) {
if(!callback(i))
return;
}
// actual logic
vec.push_back(i);
}
};
class B : public A
{
public:
B()
{
callbacks.emplace_back([this](int toAdd){return onAdd(toAdd); });
}
protected:
bool onAdd(int toAdd)
{
// do some B specific checks
std::cout << "B::onAdd()" << std::endl;
return true;
}
};
class C : public B
{
public:
C()
{
callbacks.emplace_back([this](int toAdd){return onAdd(toAdd); });
}
protected:
bool onAdd(int toAdd)
{
// do some C specific checks
std::cout << "C::onAdd()" << std::endl;
// must also call B::onAdd()
return true;
}
};
int main()
{
C c;
c.add(5);
}
打印:
A::onAdd()
B::onAdd()
C::onAdd()
相关文章:
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 初始化具有非默认构造函数的std::数组项的更好方法
- 获取从C++中同一类中的构造函数调用的方法返回的值
- 有没有一种代码密度较低的方法来使用非默认构造函数初始化数组?
- C++方法是否可以根据传递给构造函数的参数具有不同的返回类型?
- C++:将向量传递到构造函数以创建成员变量的最佳方法?
- 通过构造函数方法输出的类到类类型转换是 5500 为什么不是 5555
- 如果子类中没有构造函数方法,则错误"no matching function for call to 'LGame::LGame(String&)'"
- 复制构造函数方法的用法
- 为什么在类构造函数方法中,std::string 参数在调试时显示不同的结果?
- 我的构造函数方法不接受参数(DirectX / Windows)
- 带有常量构造函数参数的C++变量构造函数方法
- 在构造函数方法中返回一个子类
- 在模板专用化中添加单个构造函数方法
- 传递字符串指针然后检查构造函数/方法中的大小时出现问题
- 为什么基类的构造函数方法被调用两次?
- 不同的类模式:条件构造函数/方法与继承
- 我不能有一个将多个整数作为参数的构造函数方法/原型吗?阿杜伊诺
- Constexpr类与数组构造函数方法
- 通过显式调用构造函数(方法)来构造对象