Default Methods in C++ with Examples

If we write a class that has no methods in it, and the class does not inherit from another class, the compiler will add six methods to it automatically. The methods which can be automatically generated by the compiler are:

  1. Default Constructor: It is equivalent to an empty default constructor. The default constructor is a constructor which can be called with no arguments. It is called when an instance is created without initialization.
    class_name object_name;
    

    Consider a class derived from another class with the default constructor, or a class containing another class object with default constructor. The compiler needs to insert code to call the default constructors of base class/embedded object.

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    #include <iostream>
    using namespace std;
      
    class Base {
    public:
        // compiler "declares" constructor
    };
      
    class A {
    public:
        // User defined constructor
        A()
        {
            cout << "A Constructor" << endl;
        }
      
        // uninitialized
        int size;
    };
      
    class B : public A {
        // compiler defines default constructor of B, and
        // inserts stub to call A constructor
      
        // compiler won't initialize any data of A
    };
      
    class C : public A {
    public:
        C()
        {
            // User defined default constructor of C
            // Compiler inserts stub to call A's construtor
            cout << "C Constructor" << endl;
      
            // compiler won't initialize any data of A
        }
    };
      
    class D {
    public:
        D()
        {
            // User defined default constructor of D
            // a - constructor to be called, compiler inserts
            // stub to call A constructor
            cout << "D Constructor" << endl;
      
            // compiler won't initialize any data of 'a'
        }
      
    private:
        A a;
    };
      
    int main()
    {
        Base base;
      
        B b;
        C c;
        D d;
      
        return 0;
    }

    chevron_right

    
    

    Output:



    A Constructor
    A Constructor
    C Constructor
    A Constructor
    D Constructor
    
  2. Destructor: It is equivalent to an empty destructor. It calls the superclass destructor and the destructors for member fields that are not of primitive type. The general form of declaring a destructor is follows:
    class_name::~class_name;
    

    Example for Destructor:

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    #include <iostream>
    using namespace std;
      
    class Example {
      
    private:
        int a, b;
      
    public:
        // Constructor
        Example()
        {
            cout << "Constructor is called"
                 << endl;
            a = 10;
            b = 20;
        }
      
        // Destructor
        ~Example()
        {
            cout << "Destructor is called"
                 << endl;
        }
      
        // Member function
        void print()
        {
            cout << "a = " << a << endl;
            cout << "b = " << b << endl;
        }
    };
    int main()
    {
        // Object created
        Example obj; // Constructor Called
      
        // Member function called
        obj.print();
      
        return 0;
    }

    chevron_right

    
    

    Output:

    Constructor is called
    a = 10
    b = 20
    Destructor is called
    
  3. Copy Constructor: Copy constructor is a constructor which can be called with a reference to a class instance as an argument. It is called when a new copy of an instance needs to be initialized either explicitly or implicitly by the compiler, e.g., when an instance is passed by value to a function or is returned by value. It initializes every instance member with a corresponding member of the constructor’s argument.

    Below program demonstrates the use of Copy Constructor for better understanding.

  4. Copy assignment operator: It is equivalent to an assignment operator that assigns every member of its argument to a corresponding member of this instance. Note that this may lead to calls to the member’s fields own copy assignment operators.
    MyClass t1, t2; 
    
    // copy constructor is called
    MyClass t3 = t1;
    
    // copy assignment operator is called
    t2 = t1;
    

    Example for Copy Constructor and Copy Assignment Operator:

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    #include <iostream>
    using namespace std;
      
    class Line {
      
    public:
        // constructor
        Line(int len);
      
        // copy constructor
        Line(const Line& obj);
      
        void display(void);
      
    private:
        int* ptr;
    };
      
    Line::Line(int len)
    {
        // allocate memory for the pointer;
        ptr = new int;
        *ptr = len;
    }
      
    // Copy Constructor
    Line::Line(const Line& obj)
    {
        cout << "Copy constructor allocating ptr."
             << endl;
        ptr = new int;
      
        // copy the value
        *ptr = *obj.ptr;
    }
      
    void Line::display()
    {
        cout << "Length of line: "
             << *ptr << endl;
    }
      
    // Main function for the program
    int main()
    {
      
        Line l1(10), l2(0);
      
        // Copy constructor called
        Line l3 = l1;
      
        // Copy assignment operator called
        l2 = l1;
      
        l1.display();
        l2.display();
        l3.display();
      
        return 0;
    }

    chevron_right

    
    

  5. Move Constructor: The move constructor is a constructor which can be called with an rvalue reference to a class instance as an argument, typically ClassName(const ClassName&&). It is called when a new instance is initialized from a temporary object that typically is destroyed after initialization, e.g., when returning by value from a function or an explicit call as in ClassName new_instance(std::move(existing_instance)).
  6. Move Assignment Operator: C++11 defines two new functions related to move semantics: a move constructor, and a move assignment operator. Whereas the goal of the copy constructor and copy assignment is copied one object into another, the goal of the move constructor and move assignment is to move ownership of the resources from one object to another (which is much less expensive than making a copy).

    Example for Move Constructor and Move Assignment Operator:

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    #include <iostream>
    using namespace std;
      
    struct S {
        int* p;
        int n;
      
        // Move Constructor
        S(S&& other)
            : p{ exchange(other.p, nullptr) }, n{ exchange(other.n, 0) }
        {
        }
      
        // Move Assignment Operator
        S& operator=(S&& other)
        {
      
            // move p, leaving nullptr in other.p
            p = exchange(other.p, nullptr);
      
            // move n, leaving zero in other.n
            n = exchange(other.n, 0);
            return *this;
        }
    };

    chevron_right

    
    

    Defining a move constructor and move assignment work equivalently to their copy counterparts. However, whereas the copy flavours of these functions take a const lvalue reference parameter, the move flavours of these functions use non-const r-value reference parameters.

Note: It is important to be aware of these functions. The problem is not in their existence but that we are not forced to write our own and may forget to so in cases where trivial copy/initialization will not work.

For example the following program prints 1 then -2. This is because the default copy assignment operator copies the raw pointer to b2.

filter_none

edit
close

play_arrow

link
brightness_4
code

#include <bits/stdc++.h>
using namespace std;
  
class Buffer {
public:
    Buffer(int size, int* buffer)
        : size(size), buffer(buffer)
    {
    }
  
    int size;
    int* buffer;
};
  
int main()
{
    const int kBufSize = 2;
    int* buffer = new int[kBufSize]{ 1, 2 };
  
    Buffer b1 = Buffer(kBufSize, buffer);
    cout << b1.buffer[0] << endl;
  
    Buffer b2 = b1;
    b2.buffer[0] = -2;
    cout << b2.buffer[0] << endl;
  
    return 0;
}

chevron_right


Output:

1
-2

Similar problems abound when using the default constructor and destructor—fields are not initialized, memory is not reclaimed, etc. In short, we should be aware that copying and initialization objects are our responsibility.



My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.


Article Tags :
Practice Tags :


1


Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.