# Non-static member functions

From cppreference.com
< cpp‎ | language

A non-static member function is a function that is declared in a member specification of a class without a static or friend specifier.

    class S {
        int mf1(); // non-static member function declaration
        void mf2() volatile, mf3() &&; // can be cv-qualified and reference-qualified
        int mf4() const { return data; } // can be defined inline
        virtual void mf5() final; // can be virtual, can use final/override
        S() : data(12) {} // constructors are member functions too
        int data;
    };
    int S::mf1() { return 7; } // if not defined inline, has to be defined at namespace

Any function declarations are allowed, with additional syntax elements that are only available for non-static member functions: final and override specifiers, pure-specifiers, cv-qualifiers, ref-qualifiers, and member initialization lists.

A non-static member function of class X may be called

1) For an object of type X using the class member access operator
2) For an object of a class derived from X
3) Directly from within the body of a member function of X
4) Directly from within the body of a member function of a class derived from X

Calling a member function of class X on an object of any other type invokes undefined behavior.

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.

    struct S {
        int n;
        void f();
    };
    void S::f() {
        n = 1; // transformed to (*this).n = 1;
    }
    int main() {
        S s1, s2;
        s1.f(); // changes s1.n
    }

Within the body of a non-static member function of X, any unqualified-id that resolves to a static member, an enumerator or a nested type of X or of a base class of X, is transformed to the corresponding qualified-id.

    struct S {
        static int n;
        void f();
    };
    void S::f() {
        n = 1; // transformed to S::n = 1;
    }
    int main() {
        S s1, s2;
        s1.f(); // changes S::n
    }

### const-, volatile-, and ref-qualified member functions

A non-static member function can be declared with a const, volatile, or const volatile qualifier (this qualifier appears after the parameter list in the function declaration). Differently cv-qualified functions have different types and so may overload each other.

In the body of a cv-qualified function, the this pointer is cv-qualified, e.g. in a const member function, only other const member functions may be called normally. (A non-const member function may still be called if const_cast is applied or through an access path that does not involve this.)

    #include <vector>
    struct Array {
        std::vector<int> data;
        Array(int sz) : data(sz) {}
        // const member function
        int operator[](int idx) const {
                              // this has type const Array*
            return data[idx]; // transformed to (*this).data[idx];
        }
        // non-const member function
        int& operator[](int idx) {
                              // this has type Array*
            return data[idx]; // transformed to (*this).data[idx]
        }
    };
    int main()
    {
        Array a(10);
        a[1] = 1; // OK: the type of a[1] is int&
        const Array ca(10);
        ca[1] = 2; // Error: the type of ca[1] is int
    }

A non-static member function can be declared with no ref-qualifier, with an lvalue ref-qualifier (the token `&` after the parameter list) or the rvalue ref-qualifier (the token `&&` after the parameter list). During overload resolution, non-static cv-qualified member function of class X is treated as follows:

- no ref-qualifier: the implicit object parameter has type lvalue reference to cv-qualified X and is additionally allowed to bind rvalue implied object argument
- lvalue ref-qualifier: the implicit object parameter has type lvalue reference to cv-qualified X
- rvalue ref-qualifier: the implicit object parameter has type rvalue reference to cv-qualified X

    #include <iostream>
    struct S {
        void f() & { std::cout << "lvalue\n"; }
        void f() &&{ std::cout << "rvalue\n"; }
    };

    int main(){
        S s;
        s.f();            // prints "lvalue"
        std::move(s).f(); // prints "rvalue"
        S().f();          // prints "rvalue"
    }

Note: unlike cv-qualification, ref-qualification does not change the properties of the this pointer: within a rvalue ref-qualified function, *this remains an lvalue expression.

(since C++11)

### Virtual and pure virtual functions

A non-static member function may be declared virtual or pure virtual. See virtual functions and abstract classes for details.

### Special member functions

constructors and destructors are non-static member functions that use a special syntax for their declarations (see their pages for details).

Some member functions are special: under certain circumstances they are defined by the compiler even if not defined by the user. They are:

- Default constructor
- Copy constructor

- Move constructor

(since C++11)

- Copy assignment operator

- Move assignment operator

(since C++11)

- Destructor

Special member functions along with the comparison operators (since C++20) are the only functions that can be defaulted, that is, defined using = default instead of the function body (see their pages for details)

### Example

Run this code

    #include <iostream>
    #include <string>
    #include <utility>
    #include <exception>

    struct S {
        int data;

        // simple converting constructor (declaration)
        S(int val);

        // simple explicit constructor (declaration)
        explicit S(std::string str);

        // const member function (definition)
        virtual int getData() const { return data; }

    };

    // definition of the constructor
    S::S(int val) : data(val) {
        std::cout << "ctor1 called, data = " << data << '\n';
    }

    // this constructor has a catch clause
    S::S(std::string str) try : data(std::stoi(str)) {
        std::cout << "ctor2 called, data = " << data << '\n';
    } catch(const std::exception&) {
        std::cout << "ctor2 failed, string was '" << str << "'\n";
        throw; // ctor's catch clause should always rethrow
    }

    struct D : S {
        int data2;
        // constructor with a default argument
        D(int v1, int v2 = 11) : S(v1), data2(v2) {}

        // virtual member function
        int getData() const override { return data*data2; }

        // lvalue-only assignment operator
        D& operator=(D other) & {
            std::swap(other.data, data);
            std::swap(other.data2, data2);
            return *this;
        }
    };

    int main()
    {
        D d1 = 1;
        S s2("2");
        try {
             S s3("not a number");
        } catch(const std::exception&) {}
        std::cout << s2.getData() << '\n';

       D d2(3, 4);
       d2 = d1; // OK: assignment to lvalue
    //   D(5) = d1; // ERROR: no suitable overload of operator=
    }

Output:

    ctor1 called, data = 1
    ctor2 called, data = 2
    ctor2 failed, string was 'not a number'
    2
    ctor1 called, data = 3

### See also

- classes
- data members
- static data members

Retrieved from "https://en.cppreference.com/mwiki/index.php?title=cpp/language/member_functions&oldid=110459"