📜  C++中带有示例的默认方法

📅  最后修改于: 2021-05-30 20:06:25             🧑  作者: Mango

如果我们编写的类中没有方法,并且该类没有从另一个类继承,则编译器将自动向其添加六个方法。编译器可以自动生成的方法是:

  1. 默认构造函数:它等效于一个空的默认构造函数。默认构造函数是可以不带参数调用的构造函数。在创建实例而不进行初始化时调用它。
    class_name object_name;
    

    考虑从具有默认构造函数的另一个类派生的类,或包含具有默认构造函数的另一个类对象的类。编译器需要插入代码来调用基类/嵌入式对象的默认构造函数。

    #include 
    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;
    }
    
    输出:
    A Constructor
    A Constructor
    C Constructor
    A Constructor
    D Constructor
    
  2. 构函数它等效于一个空的析构函数。它调用超类析构函数和非原始类型的成员字段的析构函数。声明析构函数的一般形式如下:
    class_name::~class_name;
    

    析构函数示例:

    #include 
    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;
    }
    
    输出:
    Constructor is called
    a = 10
    b = 20
    Destructor is called
    
  3. 复制构造函数:复制构造函数是一个构造函数,可以使用对类实例的引用作为参数来调用。当实例的新副本需要由编译器显式或隐式初始化时(例如,将实例按值传递给函数或按值返回时),将函数。它使用构造函数参数的相应成员初始化每个实例成员。

    下面的程序演示了复制构造函数的使用,以便更好地理解。

  4. 复制赋值运算符:等效于一个赋值运算符,它将其参数的每个成员分配给该实例的相应成员。请注意,这可能导致调用成员字段自己的副本分配运算符。
    MyClass t1, t2; 
    
    // copy constructor is called
    MyClass t3 = t1;
    
    // copy assignment operator is called
    t2 = t1;
    

    复制构造函数和复制分配运算符的示例:

    #include 
    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;
    }
    
  5. Move构造函数: move构造函数是一个构造函数,可以使用对类实例的右值引用作为参数来调用构造函数,通常是ClassName(const ClassName &&) 。当从通常在初始化后被销毁的临时对象初始化新实例时调用该方法,例如,当从函数的值返回或像ClassName new_instance(std :: move(existing_instance))中那样通过显式调用返回时。
  6. 移动分配运算符: C++ 11定义了两个与移动语义相关的新函数:移动构造函数和移动分配运算符。尽管复制构造函数和复制分配的目标是将一个对象复制到另一个对象,但是移动构造函数和移动分配的目标是将资源的所有权从一个对象转移到另一个对象(这比制作副本要便宜得多)。

    移动构造函数和移动分配运算符的示例:

    #include 
    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;
        }
    };
    

    定义移动构造函数和移动分配工作等效于其副本副本。但是,尽管这些函数的复制风格使用const左值参考参数,但这些函数的移动风格使用非const r值参考参数。

注意:了解这些功能很重要。问题不在于它们的存在,而是我们没有被迫编写自己的文件,并且在琐碎的复制/初始化无法正常工作的情况下可能会忘记这样做。

例如,以下程序先打印1,然后再打印-2。这是因为默认的复制分配运算符将原始指针复制到b2。

#include 
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;
}
输出:
1
-2

使用默认构造函数和析构函数时,类似的问题仍然存在,例如,不初始化字段,不回收内存等。总之,我们应该意识到复制和初始化对象是我们的责任。

要从最佳影片策划和实践问题去学习,检查了C++基础课程为基础,以先进的C++和C++ STL课程基础加上STL。要完成从学习语言到DS Algo等的更多准备工作,请参阅“完整面试准备课程”