代码之家  ›  专栏  ›  技术社区  ›  fmsf

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

  •  3
  • fmsf  · 技术社区  · 17 年前

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

    是否有任何方法可以在类中创建一个函数,每当调用该类的任何其他函数时,该函数都会被调用?(就像让函数将自己附加到函数的第一个执行路径上一样)

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

    9 回复  |  直到 17 年前
        1
  •  14
  •   Scott Langham    17 年前

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

    // 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
    }
    

    好。大致沿着这些思路的东西可以发展成一种解决方案,我认为这将允许你做你想做的事情。我在那里概述的内容可能无法编译,但只是给你一个起点。

        2
  •  9
  •   ChrisW    17 年前

    对。 :-)

    • 用智能指针包裹对象
    • 从智能指针的解引用运算符自动调用对象的特殊函数(这样,每当客户端解引用智能指针时,都会调用特殊函数)。
        3
  •  4
  •   Johannes Schaub - litb    17 年前

    您可以从这个类模板派生:

    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函数的版本。但我放弃了。这需要额外的工作。然而,我仍然会 建议你做这个“自动调用函数”的事情。因为人们很容易忘记使用运算符>语法,只使用点-突然不调用预函数

    更新 :上面的版本解决了这个问题,所以人们不能再意外地调用带点的函数了。

        4
  •  3
  •   crashmstr    17 年前

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

        5
  •  2
  •   user19302 user19302    17 年前

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

        6
  •  2
  •   kshahar    17 年前

    简短的回答是:没有。

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

        7
  •  2
  •   Uli Gerhardt    17 年前

    如果我没记错的话,这就是所谓的特征 Aspect Oriented Programming .

        8
  •  0
  •   jdmichal    17 年前

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

    然而,如果你打算在每个方法的开头放一个方法调用,我建议你改为存储和调用一个方法指针。这将允许您通过一些仔细的编程和将方法设置为null来动态修改正在调用的方法,包括不调用任何方法。

        9
  •  0
  •   Choover Choover    17 年前

    我不确定你的限制是什么,所以我不知道这是否有帮助。 如果你的对象是单例,你可以将每次函数调用所调用的所有代码都放在调用中,以获得单例。

    缺点是所有其他函数调用都变得丑陋。您可能无法将该对象设置为单例。