Class default member function (C++)

1. Constructor

The constructor is a special member function with the same name as the class name. It is automatically called by the compiler when creating a class type object to ensure that each member function has an initial value and is called only once during the entire life cycle of the object.

characteristic

A constructor is a special member function. It should be noted that although the name of a constructor is called a constructor, the main task of a constructor is not to open space to create objects, but to initialize objects.
key: Opening space is a matter of the function stack frame, and calling the function to open up space.

  • The function name must be the same as the class name
  • No return value (void does not need to be written)
  • Automatically call the corresponding constructor when the object is instantiated
  • Constructors can be overloaded
class Time
{
    
    
public:
	//无参的构造函数
	Time()
	{
    
    
		cout << "None Pram" << endl;
	}


	//带参数的构造函数
	Time (int hour, int minute, int second)
	{
    
    
		_hour = hour;
		_minute = minute;
		_second = second;
		cout << _hour << ":" << _minute << ":" << _second << endl;
	}
private:
	int _hour;
	int _minute;
	int _second;
};


int main()
{
    
    
	Time t1;  //调用无参的构造函数
	Time t2(9, 19, 30);  //调用带参的构造函数
	Time t3();   //该方法调用无参构造函数会报错,该种写法是写一个返回值为Time类型函数的写法。

	
}

insert image description here

  • If there is no explicit definition constructor in the class, the C++ compiler will generate a default constructor with no parameters by default. Once the user explicitly defines the compiler, it will no longer automatically generate it.
class Time
{
    
    
public:
	带参数的构造函数
	//Time(int hour, int minute, int second)
	//{
    
    
	//	_hour = hour;
	//	_minute = minute;
	//	_second = second;
	//	cout << _hour << ":" << _minute << ":" << _second << endl;
	//}
private:
	int _hour;
	int _minute;
	int _second;
};


int main()
{
    
    
	//1.将显示定义的构造函数屏蔽以后,编译器会默认自动生成一个
	//无参的默认构造函数,因此不会报错。

	//2.如果将显示定义的构造函数展开,编译器不在生成,因为用户定义了一个。
	//此时如果还这样声明变量,就会报错,要以自己定义的方式传参。
	Time t1;  
}
  • For the default constructor generated by the compiler, it does not actually initialize the member variables of the Time class. What is the use of it?
    The default constructor generated by the compiler does not deal with built-in types (int/char/double/pointer), and calls their own default constructors for custom types (struct, class, union), etc. (Not handling built-in types is a defect of C++). C++11 adds another feature to make up for the defect, that is, member variables of built-in types can be given default values ​​​​when they are declared in the class

  • No-argument constructors, full default constructors, and constructors generated without compilers can all be considered as default constructors, and there can only be one default constructor .
    insert image description here

2. Destructor

Contrary to the function of the constructor, the destructor does not complete the destruction of the object itself, and the local object destruction is done by the compiler. When the object is destroyed, the destructor is automatically called to complete the resource cleanup work in the object . The object will be automatically destroyed when its life cycle is reached.

characteristic

  • The destructor name is the character ~ before the class name
  • no parameters no return type
  • A class can have only one destructor. If not explicitly defined, the system will automatically generate a default destructor. Note: Destructors cannot be overloaded
  • At the end of the life cycle of the object, the C++ compiler system automatically calls the destructor
class Stack
{
    
    
public:
	Stack(int capacity=3)
	{
    
    
		_arr = (int*)malloc(sizeof(int) * capacity);
		if (_arr == nullptr)
		{
    
    
			printf("malloc failed");
		}
		_capacity = capacity;
		_size = 0;
		printf("malloc success\n");
	}

	~Stack()
	{
    
    
		if (_arr)
		{
    
    
			free(_arr);
			_capacity = 0;
			_size = 0;
		}
		cout << "~stcak" << endl;
	}

private:
	int* _arr;
	int _capacity;
	int _size;
};


int main()
{
    
    
	Stack s1;
	return 0;
}

insert image description here

  • When the destructor is not explicitly defined, the compiler will automatically generate a destructor by default. It does not process the built-in type, and calls its own destructor for the custom type.
  • If there is no application resource in the class, you can directly use the default generated by the compiler without writing the destructor. Otherwise it will cause resource leakage.

3. Copy constructor

When creating an object, you can create a new object that is exactly like an existing object. This function has only a single formal parameter, which is a reference to the object of this class type (commonly const modified).

characteristic

  • The copy constructor is an overloaded form of the constructor.
  • The parameter of the copy constructor is only one and must be a reference to the type object . Using the value-passing method will cause infinite calls, because every value-passing call, the passed value is a copy construction (the value will be temporarily copied to the shape Parameters passed in the past), which will cause infinite recursion.
class Time
{
    
    
public:
	//全缺省的构造函数
	Time(int hour=0, int minute=0, int second=0)
	{
    
    
		_hour = hour;
		_minute = minute;
		_second = second;
		cout << _hour << ":" << _minute << ":" << _second << endl;
	}

	//复制本应该有两个形参,为什么只写了一个?
	//因为还隐含了一个this指针。
	//使用const是防止传进来的d被修改
	Time(const Time& d)
	{
    
    
		this->_hour = d._hour;
		_minute = d._minute;
		_second = d._second;
	}
private:
	int _hour;
	int _minute;
	int _second;
};


int main()
{
    
    
	Time t1;
	Time t2(t1);  //拷贝构造的语法,获得一个以t1完全一样的t2
	
	return 0;
}

insert image description here


insert image description here
Question 1: Why not use the = symbol to complete the copy construction?
Although both d2 and d3 can complete the task of copy construction, d1 is not intuitive and clear, and it is easy to be mistaken for assignment.
Question 2: Pointers can also complete the task of copy construction, why use references?
It is a bit redundant and troublesome to pass the address of d4. What does it mean to assign the address of d1 to d5? Obviously, comparing d2, d4, and d5, it is found that the use of references is most in line with the logic of normal people.

  • 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 TestCls {
    
    
public:
    TestCls()
    {
    
    
        cout << "TestCls()" <<endl;
        p = new int;
    }
    
    TestCls(const TestCls& d)
    {
    
    
        cout << "TestCls(const TestCls& testCls)" << endl;
        a = d.a;
        //p = testCls.p;   //如果是编译器默认生成的,会直接把指针的地址赋给p
        p = new int;

        *p = *(d.p);      //为拷贝类的p指针分配空间,实现深度拷贝
    }

    ~TestCls()
    {
    
    
        delete p;
        std::cout << "~TestCls()" << std::endl;
    }
private:
    int a;
    int* p;
};

int main()
{
    
    
    TestCls t1;
    TestCls t2(t1);

    return 0;
}

insert image description here

It can also be seen from the above example that the built-in function type (simple assignment operation) generally defaults to deep copy, but when it comes to pointers and custom classes, we must pay attention when writing constructors The problem of deep and shallow copying.


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;
	return 0;
}

Note that in this code, the member variables of d1 and the member variables of _t are next to each other in memory.
insert image description here

  • If the resource application is not involved in the class, the copy constructor can be written or not; once the resource application is involved, the copy constructor must be written, otherwise it is a shallow copy (only assigned to the pointer)

  • Typical scenarios of copy construction
    Use existing objects to create new objects; the function parameter type is a class type object; the function return value is a class type object.

class Date
{
    
    
public:
 Date(int year, int minute, int day)
 {
    
    
 cout << "Date(int,int,int):" << this << endl;
 }
 Date(const Date& d)
 {
    
    
 cout << "Date(const Date& d):" << this << endl;
 }
 ~Date()
 {
    
    
 cout << "~Date():" << this << endl;
 }
private:
 int _year;
 int _month;
 int _day;
};
Date Test(Date d)
{
    
    
 Date temp(d);
 return temp;
}
int main()
{
    
    
 Date d1(2022,1,13);
 Test(d1);
 return 0;
}

insert image description here

Therefore, in order to improve efficiency, try to use reference types when passing parameters to general objects; when returning, use references as much as possible according to actual scenarios.

4. Assignment overload function

operator overloading

In order to enhance the readability of the code, C++ introduces operator overloading, which is a function with a special function name.
Built-in types can directly use operators to operate, and the compiler knows how to operate; custom types cannot directly use operators, and the compiler does not know how to operate, so you need to implement operator overloading yourself.

Function definition syntax:

return type operator operator(parameter list)

  • Cannot create new operators, such as: operator@
  • An overloaded operator must have a class type parameter
  • As an operator of a built-in type, its meaning cannot be changed, for example: the built-in type + cannot change its meaning.
  • 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.
  • .* (rarely seen) :: (scope qualifier) ​​sizeof ?: (ternary operator) . (function call symbol) Note that the above 5 symbols cannot be overloaded
class Date
{
    
    
public:

	//构造函数
	Date(int year = 1970, int month = 1, int day = 1)
	{
    
    
		_year = year;
		_month = month;
		_day = day;
	}
	// 运算符重载
	//相当于bool operator==(Date* const this, const Date& d);
	//注意:这里左操作数是this,右操作数是d。
	bool operator==(const Date& d)
	{
    
    
		return _year == d._year
			&& _month == d._month
			&& _day == d._day;
	}

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

int main()
{
    
    
	Date d1(2023, 8, 3);
	Date d2(d1);
	Date d3(1, 1, 1);

	//相当于
	//cout<<d1.operator==(&d1, d2)<<endl;
	cout << (d1 == d2) << endl;  //结果为1
	cout << (d1 == d3) << endl;		//结果为0
	return 0;
}

assignment operator overloading

That is, assign a value to an existing object (already exists), and copy construction (assign a value to a new object).

  • Parameter type: const T&, passing reference can improve efficiency
  • Return value type: T&, return reference can improve the efficiency of return, and the purpose of return value is to support continuous assignment
  • Check if you assign a value to yourself
  • Return *this: Guarantees no error in continuous assignment.
// 赋值运算符重载
//参数加引用和const,传参更快,防止参数修改
//返回引用,防止拷贝构造。
	Date& operator=(const Date& d)
	{
    
    
		//防止  d1 = d1;
		if(this != &d)
		{
    
    
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}

		return *this;
	}

	//可以这样调用
	d2 = d1;  // d2.operator=(&d2, d1)   第一个参数是地址,第二个参数是传引用
	d3 = d2 = d1;
  • The assignment operator can only be overloaded as a member function of the class , and cannot be overloaded as a global function
    . Because the assignment operator is overloaded, if the definition that the user does not display is in the class, the compiler will automatically generate one in the class. At this time, if you declare one more globally, it will conflict with the one in the class.

  • When the user does not display the implementation, the compiler will generate a default assignment operator overload by default, which is copied byte by byte in the form of value. The built-in type member variable is directly assigned, and the custom class needs to call the self-implemented one.

const member function

Use the member function modified by const
to refer to the address of the article

take address operator overloading

//写在类里面

	//取地址运算符重载
	Date* operator&()
	{
    
    
		return this;
	}
	//通过这样设置可以保证,类外面的成员只能访问地址,不能修改地址。
	const Date* operator&()const
	{
    
    
		return this;
	}

Under normal circumstances, if we do not write this member function, the compiler will automatically generate it. So generally we don't need to write it ourselves.
So when should we write this member function?
For example, when you don't want others to get the address of this type of object, you can return nullptr, so that you will never be able to get the address of this object.

Guess you like

Origin blog.csdn.net/weixin_45153969/article/details/132032354