C++ 条件成员函数执行

C++ 条件成员函数执行,c++,C++,假设您有一个带有函数Foo::bar()的类Foo。 围绕此函数的是一个Monitor类,它围绕Foo进行包装,并通过重载operator->转发任何函数调用 此外,Monitor类有一个布尔标志execute。如果execute为true,则所有函数调用 应正常执行Foo的,但如果execute设置为false,则应跳过执行 下面的代码段显示了它的外观: #include <iostream> using namespace std; class Foo { void ba

假设您有一个带有函数
Foo::bar()
的类
Foo
。 围绕此函数的是一个
Monitor
类,它围绕
Foo
进行包装,并通过重载
operator->
转发任何函数调用

此外,Monitor类有一个布尔标志
execute
。如果
execute
为true,则所有函数调用 应正常执行Foo的,但如果
execute
设置为false,则应跳过执行

下面的代码段显示了它的外观:

#include <iostream>

using namespace std;

class Foo {
  void bar() {std::cout << "Foo::bar()";}
};

template<typename T> class Monitor<T> {
  T& ref;
  bool exec;
public:
  Monitor(T& obj) : ref(obj), exec(true) {}
  T* operator->() {/* if exec */ return &ref;}
  void setExec(bool e) {exec = e;}
};

int main() {
  Foo foo;
  Monitor<Foo> monitor(foo);

  monitor->bar(); // call Foo::bar();
  monitor.setExec(false);
  monitor->bar(); // do nothing
}
#包括
使用名称空间std;
福班{
void bar(){std::cout(){/*if exec*/return&ref;}
void setExec(boole e){exec=e;}
};
int main(){
富富,;
监视器(foo);
monitor->bar();//调用Foo::bar();
monitor.setExec(false);
监视器->栏();//什么也不做
}
这可能实现吗?显而易见的解决方案是有一个基类
IFoo
,并且 模拟实现
MockFoo
不执行任何操作,然后返回指向
MockFoo
对象的指针 当调用
操作符->
时,这会使整个过程变得相当僵硬,但您必须这样做 为要监视的任何类提供模拟对象


>,是否有更好的方法来实现这一点?

< P>如果你知道你要调用哪个函数,你可以做如下的事情。这甚至允许在函数<代码> > Exc==false < /COD>中指定函数的默认返回值。我确信我没有考虑所有可能的引用返回参数陷阱,Co。nst成员函数等,但我相信如果您想使用它,您可以对其进行调整

#include <iostream>

struct X {
    double callX(const int& x){ return x/100.;};
};

struct Y {
    int callY(const std::string& y){ return y.length();};
};

template<typename F> class Monitor;

template<typename T, typename Ret, typename ...Args>
class Monitor<Ret(T::*)(Args...)> {
    T& ref;
    Ret(T::*func)(Args...);
    Ret defaultRet;
    bool exec;
public:
    Monitor(T& ref, Ret(T::*func)(Args...), Ret defaultRet = Ret())
        : ref(ref),
          func(func),
          defaultRet(defaultRet),
          exec(true){};
    void setExec(bool e) {exec = e;};
    Ret call(Args&&... args) {
        if(exec)
            return (ref.*func)(std::forward<Args>(args)...);
        else
            return defaultRet;
    };

};

template<typename T, typename Ret, typename ...Args>
auto makeMonitor(T& x, Ret(T::*f)(Args...), Ret r = Ret()) {
    return Monitor<Ret(T::*)(Args...)>(x,f,r);
}


int main() {
    X x;
    Y y;
    auto xmon = makeMonitor(x, &X::callX);
    auto ymon = makeMonitor(y, &Y::callY);
    auto ymon_def = makeMonitor(y, &Y::callY, 123);
    std::cout << "callX(3)=" << xmon.call(3) << std::endl;
    std::cout << "callY(\"hello\")=" << ymon.call("hello") << std::endl;
    std::cout << "[default return] callY(\"hello\")=" << ymon_def.call("hello") << std::endl;
    xmon.setExec(false);
    ymon.setExec(false);
    ymon_def.setExec(false);
    std::cout << "After setExec(false):" << std::endl;
    std::cout << "callX(3)=" << xmon.call(3) << std::endl;
    std::cout << "callY(\"hello\")=" << ymon.call("hello") << std::endl;
    std::cout << "[default return] callY(\"hello\")=" << ymon_def.call("hello") << std::endl;
    return 0;
}
工作示例是

您提到的“显而易见的”解决方案可以简化一点,因此您只需定义一个额外的(模拟)类,而不需要额外的基类。如果您不介意虚拟成员函数造成的轻微性能损失,您可以这样做:

#include <iostream>

struct MockX;

struct X {
    typedef MockX mock;
    virtual double doX(int x){ return x/100.;};
};

struct MockX : X {
    virtual double doX(int x){ return 0.;};
};

struct MockY;

struct Y {
    typedef MockY mock;
    virtual int doY(std::string y){ return y.length();};
};

struct MockY : Y {
    virtual int doY(std::string y){ return 123;};
};


template <typename T>
struct Monitor {
    T& ref;
    static typename T::mock dummy;
    bool exec;
    Monitor(T& ref) : ref(ref), exec(true){};
    void setExec(bool e){exec = e;};
    T* operator->(){
        if(exec)
            return &ref;
        else
            return &dummy;
    };
};

template<typename T>
typename T::mock Monitor<T>::dummy{};

int main() {
    X x;
    Y y;
    auto xmon = Monitor<X>(x);
    auto ymon = Monitor<Y>(y);
    std::cout << "doX(3)=" << xmon->doX(3) << std::endl;
    std::cout << "doY(\"hello\")=" << ymon->doY("hello") << std::endl;
    xmon.setExec(false);
    ymon.setExec(false);
    std::cout << "After setExec(false):" << std::endl;
    std::cout << "doX(3)=" << xmon->doX(3) << std::endl;
    std::cout << "doY(\"hello\")=" << ymon->doY("hello") << std::endl;
    return 0;
}
#包括
结构MockX;
结构X{
typedef MockX mock;
虚拟双doX(intx){返回x/100;};
};
结构MockX:X{
虚双doX(intx){返回0;};
};
结构模拟;
结构{
typedef MockY mock;
虚拟整数doY(std::string y){返回y.length();};
};
结构MockY:Y{
虚拟int-doY(std::string y){return 123;};
};
模板
结构监视器{
T&ref;
静态类型名T::mock dummy;
bool-exec;
监视器(T&ref):ref(ref),exec(true){};
void setExec(boole e){exec=e;};
T*运算符->(){
如果(执行)
返回&ref;
其他的
返回&虚拟;
};
};
模板
typename T::mock Monitor::dummy{};
int main(){
X;
Y;
自动xmon=监视器(x);
自动ymon=监视器(y);

std::对如何改进我的问题或澄清我的问题没有任何评论吗?我认为如果你想能够调用被监视类的任何成员函数作为
monitor->somefunc
,除了模拟类之外没有其他方法。你是从
->
操作符返回
T*
,因此,不管它是什么,它都必须提供
somefuncde>,否则它甚至无法编译。如果您只想调用受监视类的特定方法,则可以返回调用该方法的函数对象(如果标志为false,则返回空的伪函数),而不是类本身(可能不使用
->
运算符)。您的想法告诉我这是多么困难(特别是当您必须处理返回类型时…)。我的目标是保持接口透明,因此调用
pX->callX()
monitrox->callX()
没有区别。我认为这真的不可能(因为您无法通过编程更改类)。可能是您的“显而易见的解决方案”是最好的…我会想办法让这种方法更方便。最后我使用了模拟方法。因为我已经有了一个带有基类的类结构,所以没有太大的变化。可惜没有其他方法。。。
#include <iostream>

struct MockX;

struct X {
    typedef MockX mock;
    virtual double doX(int x){ return x/100.;};
};

struct MockX : X {
    virtual double doX(int x){ return 0.;};
};

struct MockY;

struct Y {
    typedef MockY mock;
    virtual int doY(std::string y){ return y.length();};
};

struct MockY : Y {
    virtual int doY(std::string y){ return 123;};
};


template <typename T>
struct Monitor {
    T& ref;
    static typename T::mock dummy;
    bool exec;
    Monitor(T& ref) : ref(ref), exec(true){};
    void setExec(bool e){exec = e;};
    T* operator->(){
        if(exec)
            return &ref;
        else
            return &dummy;
    };
};

template<typename T>
typename T::mock Monitor<T>::dummy{};

int main() {
    X x;
    Y y;
    auto xmon = Monitor<X>(x);
    auto ymon = Monitor<Y>(y);
    std::cout << "doX(3)=" << xmon->doX(3) << std::endl;
    std::cout << "doY(\"hello\")=" << ymon->doY("hello") << std::endl;
    xmon.setExec(false);
    ymon.setExec(false);
    std::cout << "After setExec(false):" << std::endl;
    std::cout << "doX(3)=" << xmon->doX(3) << std::endl;
    std::cout << "doY(\"hello\")=" << ymon->doY("hello") << std::endl;
    return 0;
}