模拟虚方法的构造函数行为
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
的回调,但采用的是一种更加多态的方式。
当 class C
继承自 B
并想覆盖 onAdd
时,实际问题出现了。在这种情况下,B 中的实现在调用 C::add
时将被丢弃(即不被调用)。所以基本上我想实现的是一种类似构造函数的行为,我可以在 class 层次结构中的不同位置覆盖相同的方法,并且所有这些方法都被调用。
我现在的问题是:有没有possibility/design来实现这个?不过,我确信它不会像级联构造函数那样简单。
注意:不要过分关注add
示例。问题是关于类似回调的结构,而不是它是否对 add
.
有意义
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)...);
}
};
这会创建每个实例 table 待办事项 onAdd
。
创建每个 class table 更难;您需要将 table 与父类型的 table 链接起来,这需要每个 class 样板文件。
如果不自己动手,就无法让 C++ 编译器编写每个实例版本或每个 class 版本。
有涉及反射和具体化的 C++20 提议,以及元class 提议,它可能涉及像这样自动编写代码(在每个实例和每个 class基础)。
Here 是该技术正在测试的一个实例:
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++ 不会为您编写。
以下解决方案使用 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()
我会调用我的 parents onAdd()
bool C::onAdd(int toAdd) {return my_answer && B::onAdd(toAdd);}
如果您希望其他开发人员继承您的基础 class,这可能会有点令人困惑。但对于小型私有层次结构来说,它工作得很好。
我有时会包含一个 using 语句来使其更加明确
class C : public B
{
using parent=B;
bool onAdd(int toAdd) override {return my_answer && parent::onAdd(toAdd);}
};
如果您想要一个通用的解决方案,也许您可以使用带有可变参数模板的 CRTP 而不是运行时多态性。
从 this answer and this answer 中汲取灵感:
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);
我目前正在使用 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
的回调,但采用的是一种更加多态的方式。
当 class C
继承自 B
并想覆盖 onAdd
时,实际问题出现了。在这种情况下,B 中的实现在调用 C::add
时将被丢弃(即不被调用)。所以基本上我想实现的是一种类似构造函数的行为,我可以在 class 层次结构中的不同位置覆盖相同的方法,并且所有这些方法都被调用。
我现在的问题是:有没有possibility/design来实现这个?不过,我确信它不会像级联构造函数那样简单。
注意:不要过分关注add
示例。问题是关于类似回调的结构,而不是它是否对 add
.
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)...);
}
};
这会创建每个实例 table 待办事项 onAdd
。
创建每个 class table 更难;您需要将 table 与父类型的 table 链接起来,这需要每个 class 样板文件。
如果不自己动手,就无法让 C++ 编译器编写每个实例版本或每个 class 版本。
有涉及反射和具体化的 C++20 提议,以及元class 提议,它可能涉及像这样自动编写代码(在每个实例和每个 class基础)。
Here 是该技术正在测试的一个实例:
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++ 不会为您编写。
以下解决方案使用 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()
我会调用我的 parents onAdd()
bool C::onAdd(int toAdd) {return my_answer && B::onAdd(toAdd);}
如果您希望其他开发人员继承您的基础 class,这可能会有点令人困惑。但对于小型私有层次结构来说,它工作得很好。
我有时会包含一个 using 语句来使其更加明确
class C : public B
{
using parent=B;
bool onAdd(int toAdd) override {return my_answer && parent::onAdd(toAdd);}
};
如果您想要一个通用的解决方案,也许您可以使用带有可变参数模板的 CRTP 而不是运行时多态性。
从 this answer and this answer 中汲取灵感:
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);