C++ Elementary - copy construction and operator overloading (const members)

Table of contents

1. Copy constructor

1.2 Copy constructor features:

2. Default copy constructor

2.1 If not explicitly defined, the compiler will generate a default copy constructor. The default copy constructor object is copied in byte order according to memory storage. This kind of copy is called shallow copy, or value copy

3. Operator overloading

3.1 Thoughts on Operator Overloading

Note: The assignment operator can only be overloaded as a member function of a class and cannot be overloaded as a global function

3.2 Pre-++ and post-++

In order to distinguish pre- and post-++, C++ adds an int type parameter to the function of post-++ to distinguish pre-++

4. const members

 4.1 Address and const address operator


1. Copy constructor

Copy constructor: There is only a single formal parameter, which is a reference to the object of this class type (usually const decoration is commonly used), and is automatically called by the compiler when
creating a new object with an existing class type object
 

class Date
{
public:
	 Date(int year = 1900, int month = 1, int day = 1)
	 {
	 _year = year;
	 _month = month;
	 _day = day;
	 }
private:
	 int _year;
	 int _month;
	 int _day;
};
int main()
{
	 Date d1(2023,7,30);
	 Date d2(d1);//用d1初始化d2
	 return 0;
}

Note : We are initializing an existing object here

1.2 Copy constructor features:

  • Copy construction is an overloaded form of the constructor
  • The copy constructor can only have one parameter and must be a reference to a class type object. Using the value-passing method, the compiler will report an error directly,
    because it will cause infinite recursive calls
class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    // Date(const Date& d) // 正确写法
    Date(const Date d) // 错误写法:编译报错,会引发无穷递归
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }
private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d1;
    Date d2(d1);
    return 0;
}

If it is written incorrectly, it will become an infinite loop if it is called layer by layer. 

So you must add a reference when copying the construction


2. Default copy constructor

If the user does not explicitly write the copy constructor, the compiler will automatically generate a default constructor

Default constructors are done for built-in types:

值拷贝(浅拷贝)

调用自定义类型的构造函数完成拷贝

2.1 If not explicitly defined, the compiler will generate a default copy constructor . The default copy constructor object is copied in byte order according to memory storage . This kind of copy is called shallow copy , or value copy

class Time
{
public:
    Time()
    {
        _hour = 1;
        _minute = 1;
        _second = 1;

    }
    Time(const Time& t)
    {
        _hour = t._hour;
        _minute = t._minute;
        _second = t._second;
        cout << "Time::Time(const Time&)" << endl;
    }
private:
    int _hour;
    int _minute;
    int _second;
};

class Date
{
private:

    // 基本类型(内置类型)
    int _year = 1970;
    int _month = 1;
    int _day = 1;


    // 自定义类型
    Time _t;
};
int main()
{

    Date d1;
  
    // 用已经存在的d1拷贝构造d2,此处会调用Date类的拷贝构造函数
    // 但Date类并没有显式定义拷贝构造函数,则编译器会给Date类生成一个默认的拷贝构
    造函数

    Date d2(d1);
    return 0;
}

Note: In the default copy constructor generated by the compiler, built-in types are directly copied in bytes, while
custom are copied by calling their copy constructors


Let's take a look at such an example:

class Stack
{
public:
 Stack(size_t capacity = 10)//构造函数
 {
	 _array = (DataType*)malloc(capacity * sizeof(DataType));
	 if (nullptr == _array)
	 {
	 perror("malloc申请空间失败");
	 return;
	 }
	 _size = 0;
	 _capacity = capacity;
 }
 void Push(const int& data)//插入函数
 {
	 _array[_size] = data;
	 _size++;
 }
 
 ~Stack()//析构函数
 {
	 if (_array)
	 {
		 free(_array);
		 _array = nullptr;
		 _capacity = 0;
		 _size = 0;
	 }
 }

private:
	 int *_array;
	 size_t _size;
	 size_t _capacity;
};

int main()
{
	Stack s1(10);
	s1.push(1);
	s1.push(2);
	s3.push(3);
	s3.push(4);
	s3.push(5);
	Stack s2(s1);
	retrn 0;
}

 The space pointed to by array is dynamically opened up and stored in the heap area, and the space pointed to by array in s1 and s2 is the same by using the value copy method !

When the life cycle of s1 and s2 ends, their respective destructors are called respectively.
However, the pointers in the two objects point to the same space
析构函数会调用两个free释放空间!同一份空间释放两个就会出错!


3. Operator overloading

C++ introduces operator overloading to enhance the readability of the code. Operator overloading is a function with a special function name, and also has its
return value type, function name and parameter list. The return value type and parameter list are similar to ordinary functions.

The function name is: the keyword operator followed by the operator symbol that needs to be overloaded.
Function prototype: return value type operator operator (parameter list)

Notice:

  • New operators cannot be created by concatenating other symbols: e.g. operator@        
  • An overloaded operator must have a class type parameter
  • Operators used for built-in types, whose meaning cannot be changed, for example: built-in integer +, whose meaning cannot be changed
  • When overloaded as a class member function, its formal parameters appear to be 1 less than the number of operands, because the first parameter of the member function is the hidden this
  • .* :: sizeof ?: . Note that the above 5 operators cannot be overloaded. This often appears in written multiple choice questions

Function prototype:

return type     operator operator (parameter list)

Date operator+(Date d1, int x);

3.1 Thoughts on Operator Overloading

Operator overloading is for custom types, so there must be a class type parameter in the function parameter

If the operator overload is written outside the class it cannot access the private members of the class

class Date
{ 
public:
 Date(int year = 1900, int month = 1, int day = 1)
 {
        _year = year;
        _month = month;
        _day = day;
 }
 bool operator==(const Date& d2)
 {
	  return _year == d2._year;
	      && _month == d2._month
	      && _day == d2._day;
 }
private:
 int _year;
 int _month;
 int _day;
};

Because the function in the class has the this pointer by default, the pointer this represents this type of object

Note: The assignment operator can only be overloaded as a member function of a class and cannot be overloaded as a global function
 

// 赋值运算符重载成全局函数,注意重载成全局函数时没有this指针了,需要给两个参数
Date& operator=(Date& left, const Date& right)
{
    if (&left != &right)
    {
        left._year = right._year;
        left._month = right._month;
        left._day = right._day;
    }
    return left;
}

// 编译失败:
// error C2801: “operator =”必须是非静态成员

Reason : If the assignment operator is not explicitly implemented, the compiler will generate a default one.
At this time, if the user implements a global assignment operator overloadoutside the class
the assignment operator overload can only be a member function of the class

3.2 Pre-++ and post-++

In order to distinguish pre- and post-++, C++ adds an int type parameter to the function of post-++ to distinguish pre-++
//前置++
Date& operator++();


//后置++
Date& operator++(int);

Note: Although there is one more parameter in the post ++, this parameter is completely useless! It is only used to distinguish the pre ++

Let's take an example:

class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }

    // 前置++:返回+1之后的结果
    // 注意:this指向的对象函数结束后不会销毁,故以引用方式返回提高效率
    Date& operator++()
    {
        _day += 1;
        return *this;
    }

    // 后置++:
    // 前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载
    // C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器
自动传递
    // 注意:后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存
一份,然后给this+1
    // 而temp是临时对象,因此只能以值的方式返回,不能返回引用
    Date operator++(int)
    {
        Date temp(*this);
        _day += 1;
        return temp;
    }

private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d;
    Date d1(2022, 1, 13);
    d = d1++; // d: 2022,1,13 d1:2022,1,14
    d = ++d1; // d: 2022,1,15 d1:2022,1,15
    return 0;
}

4. const members

The const-modified "member function" is called a const member function . The const-modified class member function actually modifies
the implicit this pointer of the member function , indicating that any member of the class cannot be modified in the member function.

 4.1 Address and const address operator

These two default member functions generally do not need to be redefined, and the compiler will generate by default
 

class Date
{
public :
    Date* operator&()
    {
        return this ;
    }
    const Date* operator&()const
    {
        return this ;
    }
private :
    int _year ; // 年
    int _month ; // 月
    int _day ; // 日
};

These two operators generally don’t need to be overloaded, just use the default address-taking overload generated by the compiler, only in special cases,
such as wanting others to get the specified content!
 

Guess you like

Origin blog.csdn.net/m0_74459304/article/details/132130459