【c++】类与对象

C++类与对象

空类:如果一个类中不存在任何成员,我们就称之为空类、

class Date{};```

但是空类不代表类中啥都没有,在一个类中,如果没有设置成员,会自动设置6个默认的成员函数

```c
1.初始化和清理
	构造函数:完成初始化工作
	析构函数:完成清理工作
2.拷贝复制
	拷贝构造是使用同类对象初始化创建对象
	赋值运算符重载:把一个对象赋值给另一个对象
3.取地址重载
	主要是普通对象和const对象取地址

2.构造函数

1、概念

​ 构造函数是特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,并且保证每个数据成员都有合适的初始值,并在对象的生命周期内只调用一次。

2、特性

构造函数是特殊的成员函数,构造函数的名字虽然叫构造函数,但是并不代表他要开辟空间创建对象,而是初始化对象。

3、特性

1.函数名与类名相同

2.无返回值

3.对象实例化时自动调用对应的构造函数

4.构造函数可以重载

class Date
{
public:
	//无参构造函数
	Date()
	{}
	
	//带参构造函数
	Date(int year,int month,int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//初始化列表
	Date(int year,int month,int day):_year(year),
									_month(month),
									_day(day)
	{
	}
private:
	int _year;
	int _month;
	int _day;
};

void TestDate()
{
	Date d1; //调用无参构造函数
	Date d2(2019,6,16)//调用带参构造函数
}

5.如果类中没有显式定义构造函数,C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义,编译器就不在生成

class Date
{
public:
	//如果用户没有显式定义构造函数,编译器自动生成默认构造函数
	Date();
	{}
	
	//无参构造函数和全缺省的构造函数不能同时存在
	//全缺省的构造函数
	Date(int year=2010,int month = 1,int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	
private:
	int _year;
	int _month;
	int _day;
}
void TestDate()
{
	Date d;
	return 0;
}

6.无参构造函数和全缺省的构造函数都可以称为默认构造函数,且默认构造函数只有一个。注意:构造函数、全缺省构造函数、编译器生产的构造函数都可以认为是默认构造函数。

3.析构函数

  • 概念

简单来说,一个对象是通过构造函数来的,通过析构函数没的

析构函数:与构造函数相反,析构函数不是完成对象的销毁,局部对象的销毁工作是由编译器完成的,而对象在销毁时会自动调用析构函数,完成类的一些资源清理工作。

  • 特性

析构函数是特殊的成员函数

特征:

1.析构函数名是在类名前加上~

2.无参数无返回值且不能重载

3.一个类有且只有一个析构函数,若没有显式定义,系统会自动生成默认的析构函数

4.对象的生命周期结束时,C++编译系统会自动调用析构函数

#include <iostream>
#include <assert.h>
using namespace std;

typedef int DataType;
class SeqList
{
public:
	SeqList(int capacity = 3)
	{
		cout << "SeqList(int):" << this << endl;
		_array = (DataType*)malloc(sizeof(DataType)*capacity);
		if (_array == nullptr)
		{
			assert(0);
			return ;
		}
		_capacity = capacity;
		_size = 0;
	}
	//析构函数没有参数
	~SeqList()
	{
		cout << "~SeqList()" << this << endl;
		if(_array)
		{
			free(_array);
			_array = nullptr;
		}
	}
private:
	DataType * _array;
	size_t _size;
	size_t _capacity;
};

void TestSeqList()
{
	SeqList s;
}
int main()
{	
	TestSeqList();
	system("pause");
	return 0;
}

[外链图片转存失败(img-xJlWmsOB-1564716539323)(C:\Users\deorro\Desktop\111.png)]

4.拷贝构造函数

1.概念

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

2.特征

拷贝构造函数是特殊的成员函数

1、拷贝构造函数是构造函数的重载形式。

2、拷贝构造函数的参数只有一个,且必须用引用来传参,使用传值方式会导致无穷递归

#include <iostream>
using namespace std;

class Date
{
public:
	Date(int year = 2010, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)
	{
		this->_year = d._year;
		this->_month = d._month;
		this->_day = d._day;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	Date d2(d1);

	return 0;
}

若拷贝构造函数采用传值的方式,会引发对对象的拷贝,然后层层传值引发对象拷贝的递归调用,最终导致代码崩溃

3.若没有显示定义拷贝构造函数,默认的拷贝构造函数对象按照内存存储,按字节序完成拷贝,这种拷贝也被称为浅拷贝

4.编译器生成的默认拷贝构造函数已经能够实现字节序的拷贝,但仅仅针对上述这种只需要传值的Date类,当类对象为string类时

#include <iostream>
#include <assert.h>
#include <malloc.h>

using namespace std;
class String
{
public:
	String(const char* pstr = "")
	{
		_str = (char*)malloc(strlen(pstr) + 1);
		if (_str == nullptr)
		{
			assert(0);
			return;
		}
		strcpy(_str, pstr);
		cout << "String()" << endl;
	}

	~String()
	{
		if(_str)
		{
			free(_str);
		}
		cout << "~String()" << endl;
	}
private:
	char* _str;
};
void TestString()
{
	String s1("hello");
	String s2(s1);
}

int main()
{
	TestString();
	return 0;
}

5.赋值运算符重载

1.运算符重载

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

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

函数原型:返回值类型的 operator操作符

注意:

  • 不能通过连接其他符号来创建新的操作符:operator@
  • 重载操作符必须具有类类型或者枚举类型的操作数
  • 用于内置类型的操作数,其含义不能改变,如内置的整形+,不能改变其含义
  • 作为类成员的重载函数时,其形参看起来比操作数数目少一,操作符有默认的形参this,限定为第一个参数
  • .*,::,sizeof,.,?:,这5个运算符不能重载
class Date
{
public:
	Date(int year = 2010, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//若将运算符重载成全局变量,需要将成员变量设置为public,就无法保证封装性
	//这个问题可以用友元函数解决,也可以直接封装成成员函数
	//bool operator==(const Date& d1,const Date& d2)
	//{
	//return d1._month==d2._month
	//    &&d1._year==d2._year
	//   &&d1._day==d1._day;
	//   }
    //左操作数是this指着指向的调用函数对象
	bool operator==(const Date& d2)
		{
			return this->_month == d2._month
			&&(*this)._year == d2._year
			&&(*this)._day == d2._day;
		}
private:
	int _year;
	int _month;
	int _day;
};
void test()
{
	Date d1(2019,6,16);
	Date d2(2019,6,16);
	cout << (d1 == d2) << endl;
}
int main()
{
	test();
	system("pause");
	return 0;
}

2.赋值运算符重载
特点

  • 参数类型
  • 返回值
  • 检测是否是自己给自己赋值
  • 返回*this
  • 一个类如果没有显式定义赋值运算符重载,编译器会自动生成,完成对象按字节序的值拷贝
class Date
{
public:
	Date(int year = 2010, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const& Date d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	Date& operator=(const Date& d)
	{
		if(*this != d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2019,6,16);
	Date d2(2019,6,17);
	Date d3(2019,6,18);
	d1 = d2 = d3;
	return 0;
}

这里我们要实现d3给d2赋值,再用d2给d1赋值,所以在赋值运算符重载时,d3给d2赋值的过程中需要返回的是d2,即当前的*this,为了保证地址的一致性,得到的是d2而不是它的一份临时拷贝,采用了返回引用,此处返回的值生命周期大于该赋值运算符重载函数,所以返回引用没有问题。

class String
{
public:
	String(const char* pstr = "")
	{
		_str = (char*)malloc(strlen(pstr) + 1);
		if (_str == nullptr)
		{
			assert(0);
			return;
		}
		strcpy(_str,pstr);
		cout << "String" << endl;
	}
	~String()
	{
		if (_str)
		{
			free(_str);
			_str = nullptr;
		}
		cout << "~String()" << endl;
	}
private:
	char* _str;
};
int main()
{
	String s1("hello");
	String s2("world");
	s1 = s2;
	return 0;
}

这个程序会崩溃,因为同样是浅拷贝吗,却出现了资源多次释放的问题,赋值操作后,s1和s2指向了同一块内存空间,调用析构函数会导致同一块内存空间被释放多次,造成程序崩溃。

++运算符重载

前置++与后置++的区别在于先自增再运算还是先运算再自增,所以在前置++操作中,需要先进行+1操作再返回this指针,然而后置++需要创建临时变量temp来存放此时的this,再+1

class Date
{
public:
	Date(int year = 2010, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date& operator++()
	{
		_day += 1;
		return *this;
	}
	Date& operator++(int)
	{
		Date temp(*this);
		_day += 1;
		return temp;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2019, 6, 17);
	Date d2;
	d2 = ++d1;
	d2 = d1++;
	system("pause");
	return 0;
}

6.const 成员

1.const修饰类的成员函数

通常将const修饰的类成员函数称为const成员函数,const修饰类成员函数,实际修饰该成员函数的this指针,表明在该成员函数中不能对类的任何成员函数进行修改。

void Display() const----->void Display(const Date* this)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值