2

If I have a class with a virtual function and no free functions, are there any differences between this->func() and func()

class Base {
    virtual void A() { std::cout << "Base" << std::endl; };
    void B() { this->A(); };
    void C() { A(); };
};

class Derived : public Base {
    virtual void A() { std::cout << "Derived" << std::endl; };
    void B2() { this->A(); };
    void C2() { A(); };
};

Are there any differences in the execution of methods B() and C()? What about the methods B2() and C2()?

janovak
  • 1,531
  • 2
  • 12
  • 22

3 Answers3

7

In the example you've posted, there is no difference between the two syntaxes. They're completely identical.

There are two cases where there is a difference. One is if you have a template class that inherits from a type that depends on a template argument. For example:

template <typename T> class Base {
public:
    void doSomething() const {
       std::cout << "Do ALL the things!" << std::endl;
    }
};

template <typename T> class Derived: public Base<T> {
public:
    void doSomethingElse() const {
        doSomething();       // Error!
        this->doSomething(); // Okay
    }
};

Here, since Derived<T> inherits from the type Base<T>, which depends on a template argument, name lookup is done in a two-step process. If you call doSomething using the unqualified syntax, then the compiler doesn't know to look into Base<T> to find it and will report an error. However, if you say this->doSomething(), it knows that you're calling a member function and will eventually figure out that it's supposed to look in Base<T>.

The other case arises if you have a local object declared inside the function whose name is the same as a member function. For example:

class ThisIsSillyDontDoThisLikeSeriouslyDont {
public:
    void doSomething() const {
        std::cout << "Do ALL the things!" << std::endl;
    }

    void weirdFunction() const {
        auto doSomething = [] {
            std::cout << "I'm afraid there's nothing to be done" << std::endl;
        };

        doSomething();       // Calls the local function
        this->doSomething(); // Calls the member function
    }
};

This second case is so rare that I've never seen it, and I'd go so far as to say that it's really poor coding style.

Aside from these rare cases, though, there's no difference between calling a member function on yourself with and without this-> as a prefix.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • There is another case in which they are different: If a locally declared funct{ion|or} (it would be named `doSomething` in this case) in the `doSomethingElse` would shadow the method with the same name. – HolyBlackCat Jan 12 '17 at 23:43
  • 1
    @HolyBlackCat You're absolutely right. Let me go update this. – templatetypedef Jan 12 '17 at 23:44
3

Generally there is no difference, since the standard requires a call to a member function in the form A() to be equivalent to (*this).A(). Some examples where there are a difference are:

  1. If there is a block-scope declaration of A, then A() will call the function declared, whereas this->A() will always call the member function. See http://coliru.stacked-crooked.com/a/ea49916562bd4371
  2. If A is a member of a dependent base class then an attempt to call it as A() will fail; this->A() is required to postpone the name lookup until instantiation time.
Brian Bi
  • 111,498
  • 10
  • 176
  • 312
0

Cppreference concerning Non-static member functions states that there is a difference in the context of template definitions:

Within the body of a non-static member function of X, any id-expression E (e.g. an identifier) that resolves to a non-type non-static member of X or of a base class of X, is transformed to a member access expression (*this).E (unless it's already a part of a member access expression). This does not occur in template definition context, so a name may have to be prefixed with this-> explicitly to become dependent.

So in your example it does not make a difference, but in other contexts, e.g. when defining templates, it may.

Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58