In C ++, a function is created that is always executed when any other class function is called

There are so many things in C ++ that I don't know.

Is there a way to create a function within a class that will always be called whenever any other function of that class is called? (for example, if a function joins the first path of the function)

I know this is difficult, but I'm curious.

+3
source share
9 answers

Yes, with a little extra code, some indirectness and another class, and using → instead. 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
}

.. - , , , , . , , , , .

+14

.: -)

  • (, , ).
+9

:

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. . . , - " ". operator- > - pre,

: , .

+4

"" . .

+3

- . , , .

+2

: .

: ++ .

+2

, , - .

+2

, "" . , ++ .

, , . , , null.

0

I don’t know exactly what your limitations are, so I don’t know if this helps. If your object is single, you can use all the code that is called for each function call in the call to get a singleton.

Downside is all your other function calls that get ugly. And you cannot make an object single.

0
source

Source: https://habr.com/ru/post/1702788/


All Articles