2020.10.30 第3课 类和对象

本篇博客详细探讨了C++中的类和对象,包括它们的定义、权限问题、构造函数(基本构造函数和拷贝构造函数)、析构函数、深浅拷贝的概念以及this指针的使用。此外,还特别分析了构造函数在处理string对象时的细节和构造顺序与析构顺序的重要性。
摘要由CSDN通过智能技术生成

2020.10.30 第3课 类和对象

一、类和对象的定义与权限问题

	类和对象
	类:一些具有共同特征的事物的抽象
		属性:(数据成员) 行为(操作,函数:成员函数)
	对象:类的具体化
	基本语法:
	class MM        关键字class
	{
		public:
	}
	1.权限限定词 :限定类外对象对数据成员的访问
		1.1 限定对象的访问权限
		1.2 类外只能访问public:公有  公有接口
		1.3 protected:保护+private:私有
	2.构造函数
	3.析构函数
	4.拷贝构造函数(深拷贝和浅拷贝)
#include <iostream>
#include <string>
using namespace std;
class MM
{
	//默认为私有
	int age;
public:
	string name;
	//公有接口:类外法无法直接访问age num money ,通过类中添加公有接口函数
	void initData(string sName, int sAge, int sNum, int sMoney)
	{
		name = sName;
		age = sAge;
		num = sNum;
		money = sMoney;
	}
	void print()
	{
		cout << name << ":" << age << ":" << num << ":" << money << endl;
	}
protected:
	int num;
	void printInfo() {}
private:
	int money;
};
struct boy
{
	//默认为公有
protected:    C++中的结构体允许存在权限限定词

};
int main()
{
	MM myMM;
	myMM.name = "小可爱";
	//myMM.age=14;     age不能被类外对象对自己访问 类中可以
	myMM.initData("小可爱", 19, 1001, 1000000);
	myMM.print();
	return 0;
}

二、基本构造函数

构造函数:  对象创建时候初始化
	1.名字和类名相同
	2.没有返回值
	3.不需要自己调用,构造对象的时候被调用
	4.对象长相是由构造函数决定
	5.不写构造函数就存在默认的(无参)构造函数
		一旦写了构造函数,默认的不存在
	一般情况默认的构造函数是公有类型
#include <iostream>
#include <string>
using namespace std;
class X
{
public:		//是因为存在一个默认的构造函数,可以构造无参对象
	//X() = delete;
};
class MM
{
public:
	MM() { name = ""; age = 0; };
	MM(string sName, int sAge)		//写了默认的就不存在
	{
		name = sName;
		age = sAge;
	}
	void print()
	{
		cout << name << ":" << age << endl;
	}
protected:							//一般数据写保护类型
	string name;
	int age;

};
int main()
{
	X xObject;
	MM mm("mm", 18);			//MM mm;错误   创建对象必要与构造函数参数一样
	MM* p = new MM("小可爱",45);	//无名对象:也创建对象 也调用构造函数
	MM array[4];				//函数重载无参构造函数 可以用来构造数组 数组:无参的对象
	delete p;
	p = nullptr;
	return 0;
}

三、拷贝构造函数

拷贝构造函数	还可以二次初始化多次初始化
	1.拷贝构造函数也是一个构造函数
		特点:只有一个参数:对对象引用
	2.也存在一个默认的构造函数
	3.赋值的时候会调用拷贝构造函数
	4.作用:实现对象与对象之间的赋值
#include <iostream>
#include <string>
using namespace  std;
class MM
{
public:
	MM(string sName, int sAge)		//公有接口
	{
		name = sName;
		age = sAge;
	}
	//拷贝构造函数
	//MM(const MM& object)    其他地方用const修饰 也是拷贝构造函数
	MM(MM& object)
	{
		name = object.name;						//实现赋值操作
		age = object.age;
		cout << "调用自己的拷贝构造函数" << endl;	//自己写的拷贝构造函数	
	}
	void print()
	{
		cout << name << "\t" << age << endl;
	}
protected:
	string name;
	int age;
};
void printMM(MM object)		//MM object=myMM 创建了新的对象 传参就是赋值过程 调用拷贝构造函数
{
	object.print();
}
void printMM2(MM& object)	//实参的别名,没有产生新的对象  不会调用拷贝构造函数
{  
	object.print();
}
class boy
{
public:
	boy(string sName,int sAge)
	{
		name = sName;
	}
	string name;
	int age;
};
int main()
{
	MM yourMM("天狗", 18);
	//1.赋值的时候被调用
	MM myMM = yourMM;		//调用默认的拷贝构造函数
	myMM.print();
	//2.构造对象的时候被调用
	MM mm(myMM);
	mm.print();
	//3.函数传参:赋值过程  引用类型不会调用拷贝构造函数
	printMM(myMM);
	printMM2(myMM);
	//测试
	boy myBoy("夜舞",18);
	boy yourBoy(myBoy);		//存在默认拷贝构造函数
	return 0;
}

四、析构函数

析构函数:
	1.析构函数用来释放对象中的属性申请的内存 
		对象的属性做了动态内存申请,需要手动写析构函数
	2.不写析构函数存在默认的析构函数
	3.函数名:~类名  参数:无参        无法被重载
		构造函数可以被重载,因为构造函数可以有多个且可以带参数。
		析构函数不可以被重载,因为析构函数只能有一个,且不能带参数。
	4.对象死亡的时候被调用:作用域结束 不是main函数结束  生命周期结束
	5.析构是公有类型
#include <iostream>
#include <string>
using namespace std;
//析构函数调用的时候
class MM
{
public:
	~MM()
	{
		cout << "析构函数" << endl;	//墓志铭
	}
protected:
};
//类中的属性申请了内存
class student
{
public:
	student(const char* str, int sAge)			 //构造函数
	{
		name = new char[strlen(str) + 10];
		strcpy(name, str);
		age = sAge;
	}
	void print()
	{
		cout << name << ":" << age << endl;
	}
	~student()
	{
		delete[]name;
		cout << "释放成功" << endl;
	}
protected:
	char* name;
	int age;
};
int main()
{
	{   //作用域分辨符 提前结束生命周期
		MM mm;
		MM* p = new MM;  //动态内存申请的需要手动释放
		delete p;
		p = nullptr;	 //收尾工作
	}
	//手写:
	{
		student myStudent("yykkk", 18);
		myStudent.print();
	}

	return 0;
}

五、深浅拷贝

	默认的拷贝都是浅拷贝
		浅拷贝:没有申请内存情况下
		浅拷贝释放时导致释放失败 两个指针指向同一个位置
		两个位置重复被释放导致析构问题
#include <iostream>
#include <string.h>
#include <string>
using namespace std;
class MM
{
public:
	MM(const char* str)
	{
		name = new char[strlen(str) + 1];
		strcpy(name, str);
	}
	MM(MM& object)
	{
		//name = object.name;
		name = new char[strlen(object.name) + 1];
		strcpy(name, object.name);
	}
	~MM()
	{
		delete[] name;
	}
protected:
	char* name;		//习惯于数据成员写成protected
};
int main()
{
	{
		MM mm("小仙女");
		MM myMM = mm;
	}
	string str = "Iloveyou";   //赋值 拷贝构造函数
	string str1(str);		   //创建新对象 调用拷贝构造函数
	return 0;
}

六、this指针

this:代表每一个对象的首地址   //*this 对象本身
	可以避免形参名字和数据成员名字相同的问题
	用来区别
#include <iostream>
#include <string>
using namespace std;
class MM
{
public:
	MM(string name, int age)
	{
		this->name = name;
		//this->age = age;    
		(*this).age = age;   //*this 对象本身
	}
	void print()
	{
		cout << this->age << ":" << age << endl;
	}
	//返回对象本身
	MM& returnObject()		 //MM returnObject()
	{
		return *this;
	}
protected:
	string name;
	int age;
};
int main()
{
	MM mm("张三", 18);
	//无实际作用
	mm.returnObject().returnObject().returnObject().returnObject().returnObject().print();

	MM yourMM("里斯", 29);
	yourMM.returnObject().print();


	return 0;
}

七、构造顺序与析构顺序

	1.构造函数顺序和构造顺序相反
	2.delete可以直接调用析构函数
	3.静态变量是最后调用析构函数     程序运行之前分配内存
		函数传参 隐藏的赋值操作
#include <iostream>
#include <string>
using namespace std;
class A
{
public:
	A()					//构造函数
	{
		cout << "A";
	}
						//存在默认的拷贝构造函数
	void print()
	{
		cout << "B";
	}
	~A()				//析构函数没有参数不能重载
	{
		cout << "C";	
	}
};
void print(A a)		//A a=实参 //存在临时对象  调用默认的拷贝构造函数
{
	a.print();		//B C
}
int main()
{
	{					//预符号:提早把对象干掉 vs2013
		//1.正常情况构造顺序和析构顺序相反
		A a;				//A
		print(a);			//BC!!
		A array[3];			//AAA   CCC C			
	}	
	cout << endl;
	{
		//new出来,什么时候delete 什么时候调用析构函数
		A a;				//A
		A* p = new A;		//A		//手动写的手动delete
		delete p;
		p = nullptr;		//C
		A b;				//A     C C
	}
	cout << endl;	
	{
		A a;				//A
		A* p = new A;		//A
		A b;				//A   CC
	}
	cout << endl;
	{
		static A static_A;	
	}
	return 0;
}

八、构造函数看string

#include <string>
#include <iostream>
#include <string.h>
using namespace std;
class myString
{
public:
	myString(const char* str)
	{
		this->str = new char[strlen(str) + 1];
		strcpy(this->str, str);
	}
	myString(myString& object)
	{
		this->str = new char[strlen(object.str) + 1];
		strcpy(this->str, object.str);
	}
	char* c_str()
	{
		return str;
	}
protected:
	char* str;
};
int main()
{
	//构造函数
	string str("Iloveyou");
	myString myStr("Iloveyou");

	//拷贝构造函数
	string str1(str);
	string str2 = str1;

	myString myStr1(myStr);
	myString myStr2 = myStr1;

	printf("%s\n", str2.c_str());
	cout << str2 << endl;
	printf("%s\n", myStr2.c_str());
	//cout << myStr2 << endl; C++运算符重载  后面可以实现
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值