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

时间:2022-01-06 16:01:08

C++ has so much stuff that I don't know.

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

Is there any way to create a function within a class, that will always be called whenever any other function of that class is called? (like making the function attach itself to the first execution path of a function)

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

I know this is tricky but I'm curious.

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

9 个解决方案

#1


Yes-ish, with a bit of extra code, some indirection and another class and using the -> instead of the . operator.

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

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

Well.. something roughly along those lines could be developed into a solution that I think would allow you to do what you want. What I've sketched out there probably won't compile, but is just to give you a starting point.

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

#2


Yes. :-)

  • Wrap the object in a smart pointer
  • 将对象包装在智能指针中

  • Invoke the object's special function automatically from the smart pointer's dereferencing operators (so that the special function is invoked whenever a client dereferences the smart pointer).
  • 从智能指针的解除引用操作符自动调用对象的特殊功能(以便在客户端取消引用智能指针时调用特殊功能)。

#3


You can derive from this class template:

您可以从此类模板派生:

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); 
    }
};

And use it like 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!
}

Previously i had a version that called post functions too. But i dropped it. It would have needed additional work. However, i would still not recommend you to do this "call function automatically" thingy. Because one can easily forget to use the operator-> syntax and just use the dot - and suddenly have the pre function not called

以前我有一个叫post功能的版本。但我放弃了它。它本来需要额外的工作。但是,我仍然不建议你这样做“自动调用功能”的东西。因为人们很容易忘记使用operator->语法并只使用点 - 并突然没有调用pre函数

Update: The version above takes care of that, so one cannot accidentally call functions with the dot anymore.

更新:上面的版本负责处理,因此不能再意外地使用点调用函数。

#4


There is no "automatic" way to do this. You would need to add a call to the function in each class method.

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

#5


Without some insane code injection, this is not possible. However, you can of course call that function manually.

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

#6


The short answer: No.

简短回答:没有。

The long answer: there is no such thing in the C++ standard.

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

#7


If I'm not mistaken this is a feature of what is called Aspect Oriented Programming.

如果我没有弄错,这就是所谓的面向方面编程的一个特性。

#8


As others have said, there is no "automatic" way to do this. As in, the C++ standard does not define a way to do this.

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

However, if you are going to go the route of putting a method call at the beginning of every method, I would recommend you instead store and invoke a method pointer instead. This will allow you to dynamically modify which method is being called, including none with some careful programming and setting the method to null.

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

#9


I'm not sure exactly what your restrictions are, so I don't know if this helps. If your object a singleton, you could stick all the code that gets called for every function call in the call to get the singleton.

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

Downside is all your other functions calls get ugly. And you may not be able to make the object a singleton.

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

#1


Yes-ish, with a bit of extra code, some indirection and another class and using the -> instead of the . operator.

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

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

Well.. something roughly along those lines could be developed into a solution that I think would allow you to do what you want. What I've sketched out there probably won't compile, but is just to give you a starting point.

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

#2


Yes. :-)

  • Wrap the object in a smart pointer
  • 将对象包装在智能指针中

  • Invoke the object's special function automatically from the smart pointer's dereferencing operators (so that the special function is invoked whenever a client dereferences the smart pointer).
  • 从智能指针的解除引用操作符自动调用对象的特殊功能(以便在客户端取消引用智能指针时调用特殊功能)。

#3


You can derive from this class template:

您可以从此类模板派生:

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); 
    }
};

And use it like 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!
}

Previously i had a version that called post functions too. But i dropped it. It would have needed additional work. However, i would still not recommend you to do this "call function automatically" thingy. Because one can easily forget to use the operator-> syntax and just use the dot - and suddenly have the pre function not called

以前我有一个叫post功能的版本。但我放弃了它。它本来需要额外的工作。但是,我仍然不建议你这样做“自动调用功能”的东西。因为人们很容易忘记使用operator->语法并只使用点 - 并突然没有调用pre函数

Update: The version above takes care of that, so one cannot accidentally call functions with the dot anymore.

更新:上面的版本负责处理,因此不能再意外地使用点调用函数。

#4


There is no "automatic" way to do this. You would need to add a call to the function in each class method.

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

#5


Without some insane code injection, this is not possible. However, you can of course call that function manually.

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

#6


The short answer: No.

简短回答:没有。

The long answer: there is no such thing in the C++ standard.

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

#7


If I'm not mistaken this is a feature of what is called Aspect Oriented Programming.

如果我没有弄错,这就是所谓的面向方面编程的一个特性。

#8


As others have said, there is no "automatic" way to do this. As in, the C++ standard does not define a way to do this.

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

However, if you are going to go the route of putting a method call at the beginning of every method, I would recommend you instead store and invoke a method pointer instead. This will allow you to dynamically modify which method is being called, including none with some careful programming and setting the method to null.

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

#9


I'm not sure exactly what your restrictions are, so I don't know if this helps. If your object a singleton, you could stick all the code that gets called for every function call in the call to get the singleton.

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

Downside is all your other functions calls get ugly. And you may not be able to make the object a singleton.

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