在c ++中创建一个在调用类的任何其他函数时始终运行的函数

时间:2009-02-05 21:28:33

标签: c++ syntax

C ++有很多我不知道的东西。

有没有办法在类中创建一个函数,只要调用该类的任何其他函数,它就会被调用? (比如使函数将自身附加到函数的第一个执行路径)

我知道这很棘手,但我很好奇。

9 个答案:

答案 0 :(得分:14)

是的,有一些额外的代码,一些间接和另一个类,并使用 - >而不是。操作

// The class for which calling any method should call PreMethod first.
class DogImplementation
{
public:
   void PreMethod();
   void Bark();
private:
   DogImplementation(); // constructor private so can only be created via smart-pointer.
   friend class Dog; // can access constructor.
};

// A 'smart-pointer' that wraps a DogImplementation to give you
// more control.
class Dog
{
public:
   DogImplementation* operator -> ()
   {
       _impl.PreMethod();
       return &_impl;
   }
private:
   DogImplementation _impl;
};

// Example usage of the smart pointer. Use -> instead of .
void UseDog()
{
  Dog dog;
  dog->Bark();    // will call DogImplementation::PreMethod, then DogImplementation::Bark
}

嗯......大致沿着这些方向发展的东西可以发展成一个我认为可以让你做你想做的解决方案。我在那里描绘的内容可能无法编译,但只是为了给你一个起点。

答案 1 :(得分:9)

是。 : - )

  • 用智能指针包裹对象
  • 从智能指针的解除引用操作符自动调用对象的特殊功能(以便在客户端解除引用智能指针时调用特殊功能)。

答案 2 :(得分:4)

您可以从此类模板派生:

namespace detail {
struct const_tag;
struct nonconst_tag;

/* T is incomplete yet when pre_call is instantiated. 
 * so delay lookup of ::impl until call to operator-> 
 * happened and this delay_lookup is instantiated */
template<typename U, typename>
struct delay_lookup; 

template<typename U>
struct delay_lookup<U, nonconst_tag>
{
    typedef typename U::template get_impl<
        typename U::derived_type>::type impl_type;
    impl_type* u;
    delay_lookup(impl_type* u):u(u) { }
    impl_type* operator->() { return u; }
};

template<typename U>
struct delay_lookup<U, const_tag> {
    typedef typename U::template get_impl<
        typename U::derived_type>::type const impl_type;
    impl_type* u;
    delay_lookup(impl_type* u):u(u) { }
    impl_type* operator->() { return u; }
};

} // detail::

template<typename T>
struct pre_call {
private:
    friend class detail::delay_lookup<pre_call, detail::const_tag>;
    friend class detail::delay_lookup<pre_call, detail::nonconst_tag>;
    typedef T derived_type;

    /* pre_call is the friend of T, and only it
     * is allowed to access T::impl */
    template<typename U> struct get_impl {
        typedef typename U::impl type;
    };

protected:
    typedef boost::function<void(T const&)> fun_type;
    fun_type pre;

    template<typename Fun>
    pre_call(Fun pre):pre(pre) { }

public:
    /* two operator->: one for const and one for nonconst objects */
    detail::delay_lookup<pre_call, detail::nonconst_tag> operator->() { 
        pre(*get_derived()); 
        return detail::delay_lookup<pre_call, 
            detail::nonconst_tag>(&get_derived()->d);
    }

    detail::delay_lookup<pre_call, detail::const_tag> operator->() const { 
        pre(*get_derived()); 
        return detail::delay_lookup<pre_call, 
            detail::const_tag>(&get_derived()->d);
    }

private:
    T * get_derived() { 
        return static_cast<T *>(this); 
    }

    T const* get_derived() const { 
        return static_cast<T const*>(this); 
    }
};

并像这样使用它:

struct foo : pre_call<foo> {
private:
    /* stuff can be defined inline within the class */
    struct impl { 
        void some() const {
            std::cout << "some!" << std::endl;
        }

        void stuff()  {
            std::cout << "stuff!" << std::endl;
        }
    };

    void pre() const { 
        std::cout << "pre!" << std::endl;
    }

    friend struct pre_call<foo>;
    impl d;

public:
    foo():pre_call<foo>(&foo::pre) { }    
};

int main() {
    foo f;
    f->some();
    f->stuff();
    // f.some(); // forbidden now!
}

以前我有一个叫post功能的版本。但我放弃了它。它本来需要额外的工作。但是,我仍然会建议您自动执行此“自动调用功能”。因为人们很容易忘记使用操作员 - >语法,只需使用点 - 突然有pre函数不叫

更新:上面的版本处理了这个问题,因此不能再意外地使用点调用函数。

答案 3 :(得分:3)

没有“自动”方式来做到这一点。您需要在每个类方法中添加对函数的调用。

答案 4 :(得分:2)

如果没有一些疯狂的代码注入,这是不可能的。但是,您当然可以手动调用该函数。

答案 5 :(得分:2)

答案简短:不。

答案很长:C ++标准中没有这样的东西。

答案 6 :(得分:2)

如果我没有弄错,这就是所谓Aspect Oriented Programming的一个特征。

答案 7 :(得分:0)

正如其他人所说,没有“自动”方式来做到这一点。同样,C ++标准没有定义这样做的方法。

但是,如果您打算在每个方法的开头放置一个方法调用的路径,我建议您改为存储并调用方法指针。这将允许您动态修改正在调用的方法,包括没有仔细编程并将方法设置为null。

答案 8 :(得分:0)

我不确定你的限制是什么,所以我不知道这是否有帮助。 如果你的对象是单例,你可以在调用中为每个函数调用粘贴所有调用的代码来获取单例。

下行是你所有其他函数调用变得难看。而且你可能无法使对象成为单身人士。