【C++】类的默认成员函数

2024-06-14 1492阅读

类的默认成员函数

  • 类的六个默认成员函数
  • 构造函数
    • 构造函数的概念
    • 构造函数的特性
    • 析构函数
      • 析构函数的概念
      • 析构函数的特性
      • 构造函数与析构函数的调用顺序
      • 拷贝构造
      • 拷贝构造的概念
      • 拷贝构造的特性
      • 赋值运算符重载
        • 运算符重载
        • 赋值运算符重载
        • 前置++与后置++重载
        • 输入输出流重载
        • const修饰成员
        • 实现完整的日期系统
        • 取地址操作符重载
        • const取地址操作符重载

          类的六个默认成员函数

          当一个类中什么成员都没有时被称为空类。

          空类:即任何类在什么都不写时,编译器会自动生成6个默认成员函数。

          默认成员函数:用户没有显式实现,编译器会自动生成的成员函数称为默认成员函数。

          构造函数

          构造函数的概念

          class Data
          {
          public:
          	void Init(int year = 2000, int month = 1, int day = 1)
          	{
          		_year = year;
          		_month = month;
          		_day = day;
          	}
          	void Print()
          	{
          		cout 
          	Data d1;
          	d1.Init();
          	d1.Print();
          	Data d2;
          	d2.Init(2024,6,8);
          	d2.Print();
          	return 0;
          }
          
          public:
          	Data(int year = 2000, int month = 1, int day = 1)
          	{
          		_year = year;
          		_month = month;
          		_day = day;
          	}
          private:
          	int _year;
          	int _month;
          	int _day;
          };
          int main(void)
          {
          	Data d1();
          	return 0;
          }
          
          public:
          	//带参数的构造函数
          	Data(int year, int month, int day)
          	{
          		_year = year;
          		_month = month;
          		_day = day;
          	}
          	//不带参数的构造函数
          	Data()
          	{
          		_year = 2000;
          		_month = 1;
          		_day = 1;
          	}
          private:
          	int _year;
          	int _month;
          	int _day;
          };
          int main(void)
          {
          	//调用带参数的构造函数
          	Data d1(2024,6,8);
          	//调用不带参数的构造函数
          	Data d2;
          	return 0;
          }
          
          public:
          	void Print()
          	{
          		cout 
          	Data d1;
          	d1.Print();
          	return 0;
          }
          
          public:
          	void Print()
          	{
          		cout 
          public:
          	//无参构造函数
          	Data()
          	{
          		_year = 2000;
          		_month = 1;
          		_day = 1;
          	}
          	//全参构造函数
          	Data(int year = 2000,int month = 1, int day = 1)
          	{
          		_year = year;
          		_month = month;
          		_day = day;
          	}
          private:
          	int _year;
          	int _month;
          	int _day;
          };
          int main(void)
          {
          	Data d1;
          	return 0;
          }
          
          public:
          	Data(int year = 2000, int month = 1, int day = 1)
          	{
          		this-_year = year;
          		this-_month = month;
          		this-_day = day;
          	}
          	~Data()
          	{
          		_year = 0;
          		_month = 0;
          		_day = 0;
          	}
          private:
          	int _year;
          	int _month;
          	int _day;
          };
          
          public:
          	Data(int year = 2000, int month = 1, int day = 1)
          	{
          		cout 
          		cout 
          	Data d1;
          	return 0;
          }
          
          public:
          	Stack(int capacity = 4)
          	{
          		_arr = (int*)malloc(sizeof(int) * capacity);
          		if (_arr == nullptr)
          		{
          			perror("malloc fail");
          			return;
          		}
          		_capacity = capacity;
          		_size = 1;
          	}
          	~Stack()
          	{
          		free(_arr);
          		_arr = nullptr;
          		_size = 1;
          		_capacity = 0;
          	}
          	void Push(int x)
          	{
          		if (this-_capacity == this-_size)
          		{
          			int* arr = (int*)realloc(this-_arr, sizeof(int) * this-_capacity * 2);
          			if (arr == nullptr)
          			{
          				perror("realloc fail");
          				return;
          			}
          			this-_arr = arr;
          			this-_capacity *= 2;
          		}
          		this-_arr[this-_size - 1] = x;
          		this-_size++;
          	}
          	void Pop()
          	{
          		this-_arr[this-_size - 1] = 0;
          		this-_size--;
          	}
          private:
          	int* _arr;
          	int _size;
          	int _capacity;
          };
          int main(void)
          {
          	Stack s1;
          	s1.Push(1);
          	s1.Push(2);
          	s1.Push(3);
          	s1.Push(4);
          	s1.Pop();
          	return 0;
          }
          
          public:
          	Stack(int capacity = 4)
          	{
          		_arr = (int*)malloc(sizeof(int) * capacity);
          		if (_arr == nullptr)
          		{
          			perror("malloc fail");
          			return;
          		}
          		_capacity = capacity;
          		_size = 1;
          	}
          	void Push(int x)
          	{
          		if (this-_capacity == this-_size)
          		{
          			int* arr = (int*)realloc(this-_arr, sizeof(int) * this-_capacity * 2);
          			if (arr == nullptr)
          			{
          				perror("realloc fail");
          				return;
          			}
          			this->_arr = arr;
          			this->_capacity *= 2;
          		}
          		this->_arr[this->_size - 1] = x;
          		this->_size++;
          	}
          	void Pop()
          	{
          		this->_arr[this->_size - 1] = 0;
          		this->_size--;
          	}
          private:
          	int* _arr;
          	int _size;
          	int _capacity;
          };
          int main(void)
          {
          	Stack s1;
          	s1.Push(1);
          	s1.Push(2);
          	s1.Push(3);
          	s1.Push(4);
          	s1.Pop();
          	return 0;
          }
          

          【C++】类的默认成员函数

          所以,一般情况下如果没有动态内存申请,析构函数可以不写,例如:Data类;但是如果有动态内存申请,就需要显式写析构函数释放资源,否则会造成内存泄漏。例如:栈的实现。

          构造函数与析构函数的调用顺序

          • 类的析构函数调用一般按照构造函数调用的相反顺序调用,但是需要注意static对象的存在,因为static改变了对象的生存作用域,需要等待程序结束后才可析构释放对象。

          • 全局对象先于局部对象进行构造。

          • 局部对象按照顺序进行构造,无论是否为static对象。

          • static修饰的对象会在局部对象析构后进行析构。

            拷贝构造

            拷贝构造的概念

            创建对象时,需要创建一个与已存在对象一模一样的新对象,就需要用到拷贝构造。

            拷贝构造:只有单个形参,该形参是对本类型对象的引用(一般常用const修饰),在用已存在的类型对象创建新对象时由编译器自动调用。

            拷贝构造的特性

            拷贝构造函数也是特殊的成员函数,其特征如下:

            1.拷贝构造函数时构造函数的一个重载形式,所有书写格式与构造函数类似,但是参数类型不同。

            2.拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器之间报错,因为会引发无穷递归调用。

            观察下面代码:

            class Data
            {
            public:
            	Data(int year = 2000, int month = 1, int day = 1)
            	{
            		cout _month = month;
            		this->_day = day;
            	}
            	~Data()
            	{
            		cout 
            		_year = d._year;
            		_month = d._month;
            		_day = d._day;
            	}
            private:
            	int _year;
            	int _month;
            	int _day;
            };
            int main(void)
            {
            	Data d1;
            	Data d2(d1);
            	return 0;
            }
            
            public:
            	Data(int year = 2000, int month = 1, int day = 1)
            	{
            		this-_year = year;
            		this-_month = month;
            		this->_day = day;
            	}
            	~Data()
            	{
            		_year = 0;
            		_month = 0;
            		_day = 0;
            	}
            	//拷贝构造函数
            	//传值
            	Data(const Data& d)
            	{
            		_year = d._year;
            		_month = d._month;
            		_day = d._day;
            	}
            private:
            	int _year;
            	int _month;
            	int _day;
            };
            int main(void)
            {
            	Data d1;
            	Data d2(d1);
            	return 0;
            }
            

            【C++】类的默认成员函数

            3.如果没有显式定义,编译器会生成默认的拷贝构造函数,默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫浅拷贝,或者值拷贝。

            (1)内置类型成员完成值拷贝、浅拷贝。

            (2)自定义类型成员会调用他的拷贝构造。

            观察代码:

            class Stack
            {
            public:
            	Stack(int capacity = 4)
            	{
            		_arr = (int*)malloc(sizeof(int) * capacity);
            		if (_arr == nullptr)
            		{
            			perror("malloc fail");
            			return;
            		}
            		_capacity = capacity;
            		_size = 1;
            	}
            	void Push(int x)
            	{
            		if (this->_capacity == this->_size)
            		{
            			int* arr = (int*)realloc(this->_arr, sizeof(int) * this->_capacity * 2);
            			if (arr == nullptr)
            			{
            				perror("realloc fail");
            				return;
            			}
            			this->_arr = arr;
            			this->_capacity *= 2;
            		}
            		this->_arr[this->_size - 1] = x;
            		this->_size++;
            	}
            	void Pop()
            	{
            		this->_arr[this->_size - 1] = 0;
            		this->_size--;
            	}
            private:
            	int* _arr;
            	int _size;
            	int _capacity;
            };
            int main(void)
            {
            	Stack s1;
            	s1.Push(1);
            	s1.Push(2);
            	s1.Push(3);
            	s1.Push(4);
            	s1.Pop();
            	Stack s2(s1);
            	return 0;
            }
            

            【C++】类的默认成员函数

            以栈为例,栈不可以使用默认拷贝构造,栈默认生成的拷贝构造会将俩个指针指向同一个栈,在析构时,后面拷贝的指针会先析构,而前面被拷贝的指针会后析构,一个堆区被析构俩次,编译器会报错,同时如果修改其中一个值,会影响另一个。

            栈拷贝构造的正确代码是:

            	Stack(const Stack& s)
            	{
            		_arr = (int*)malloc(sizeof(int) * s._capacity);
            		if (_arr == nullptr)
            		{
            			perror("malloc fail");
            			return;
            		}
            		memcpy(_arr, s._arr, sizeof(int) * s._size);
            		_size = s._size;
            		_capacity = s._capacity;
            	}
            

            【C++】类的默认成员函数

            需要动态开辟的都需要自己实现深拷贝,而像日期类可以不写拷贝构造,默认生成的拷贝构造就可以用。

            赋值运算符重载

            运算符重载

            C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通函数类似。

            函数名字为:关键字operator后面接需要重载的运算符符号。

            函数原型:返回值类型 operator操作符(参数列表)

            • 内置类型可以通过编译器计算,而自定义类型也可以向内置类型一样,需要通过运算符重载,进行加、减、比较等。

              以Date日期类举例:是否使用重载运算符,是观察这个运算符对这个类是否有意义,例如:日期相减可以计算相差天数,而日期相加却没有意义。

              下面演示日期比较大小:

              class Date
              {
              public:
              	//Date构造
              	Date(int year = 2000,int month = 1, int day = 1)
              	{
              		_year = year;
              		_month = month;
              		_day = day;
              	}
              	//Date默认析构,默认拷贝
              	//
              //private:
              	int _year;
              	int _month;
              	int _day;
              };
              bool operator>(const Date& d1, const Date& d2)
              {
              	if (d1._year > d2._year)
              	{
              		return true;
              	}
              	else if (d1._year == d2._year && d1._month > d2._month)
              	{
              		return true;
              	}
              	else if (d1._year == d2._year && d1._month == d2._month && d1._day > d2._day)
              	{
              		return true;
              	}
              	return false;
              }
              int main(void)
              {
              	Date d1(2024, 6, 10);
              	Date d2(2024, 5, 20);
              	if (d1 > d2)
              	{
              		cout 
              		cout (d1,d1)是相同的,第二种方式相当于调用函数。 
              
              int main(void)
              {
              	Date d1(2024, 6, 10);
              	Date d2(2024, 5, 20);
              	//第一种方式
              	if (d1 > d2)
              	{
              		cout 
              		cout 
              		cout 
              		cout 
              public:
              	//Date构造
              	Date(int year = 2000, int month = 1, int day = 1)
              	{
              		_year = year;
              		_month = month;
              		_day = day;
              	}
              	//Date默认析构,默认拷贝
              	//比较大小的运算符重载
              	bool operator(const Date& d)
              	{
              		if (_year  d._year)
              		{
              			return true;
              		}
              		else if (_year == d._year && _month  d._month)
              		{
              			return true;
              		}
              		else if (_year == d._year && _month == d._month && _day  d._day)
              		{
              			return true;
              		}
              		return false;
              	}
              private:
              	int _year;
              	int _month;
              	int _day;
              };
              int main(void)
              {
              	Date d1(2024, 6, 10);
              	Date d2(2024, 5, 20);
              	//第一种方式
              	if (d1  d2)
              	{
              		cout 
              		cout 
              		cout 
              		cout 
              		_year = d._year;
              		_month = d._month;
              		_day = d._day;
              	}
              
              	//调用拷贝构造函数
              	Date d1(2024, 6, 10);
              	Date d2 = d1;
              	//调用运算符重载函数
              	Date d3(2024, 5, 20);
              	Date d4(2003, 2, 3);
              	d3 = d4;
              	return 0;
              }
              
              		_year = d._year;
              		_month = d._month;
              		_day = d._day;
              		return *this;
              	}
              
              		_year = d._year;
              		_month = d._month;
              		_day = d._day;
              		return *this;
              	}
              
              		if (this != &d)
              		{
              			_year = d._year;
              			_month = d._month;
              			_day = d._day;
              		}
              		return *this;
              	}
              
              		_day = _day + 1;
              		return *this;
              	}
              
              		Date tmp(*this);
              		_day = _day + 1;
              		return tmp;
              	}
              
              	out 
              	int i = 10;
              	cout 
              public:
              	//公有的成员函数
              	int GetYear()
              	{
              		return _year;
              	}
              	int GetMonth()
              	{
              		return _month;
              	}
              	int GetDay()
              	{
              		return _day;
              	}
              private:
              	int _year;
              	int _month;
              	int _day;
              };
              //全局的流插入操作符
              void operator
              	out 
              public:
              	//友元函数声明
              	friend void operator
              	out 
              	out 
              public:
              	//友元函数声明
              	friend ostream& operator
              	out 
              public:
              	//友元函数声明
              	friend istream& operator(istream& in,  Date& d);
              private:
              	int _year;
              	int _month;
              	int _day;
              };
              //全局的流提取操作符
              istream& operator(istream& in, Date& d)
              {
              	in  d._year  d._month  d._day;
              	return in;
              }
              
              public:
              	//全缺省的构造函数
              	Date(int year = 2000, int month = 1, int day = 1);
              	//析构函数
              	~Date();
              	//拷贝构造函数
              	Date(const Date& d);
              	//赋值运算符重载
              	Date& operator=(const Date& d);
              	//打印
              	void Print() const
              	{
              		cout 
              	if (month  0 && month 
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]