C++易错知识点笔记(五)写一个类的例子记忆类的正确书写,成员权限,构造函数,析构函数,深拷贝与浅拷贝

C++易错知识点笔记(五)写一个类的例子记忆类的正确书写,成员权限,构造函数,析构函数,深拷贝与浅拷贝,第1张

C++易错知识点笔记(五)写一个类的例子记忆类的正确书写,成员权限,构造函数,析构函数,深拷贝与浅拷贝

这里写一个钟表类,读者可以通过复制整个代码到vs中运行试验,从这个例子中体会一个类的基本写法,下一篇博客讲解继承,在观察这个例子的时候,注意以下几点:
1,关注类的简单语法
2,关注类的成员变量一般私有
3,关注类的构造函数的一般写法与调用
4,关注析构函数的使用,析构函数只有一个,如果类中有动态申请的内存资源(堆资源),一定要在析构函数中释放。
5,关注拷贝构造函数的使用,深拷贝与浅拷贝;默认的拷贝构造函数为浅拷贝,被复制对象中如果有堆资源时,两者共用该堆资源。这种情况下两个对象析构时会调用两次析构函数,即对同一片堆内存释放两次,程序奔溃。因此如果类中有堆资源时,要重写拷贝构造函数,新对象也申请属于自己的堆资源。
6,关注类对象的创建方法——分为栈对象和堆对象,详情见代码。

#define _CRT_SECURE_NO_WARNINGS
#include
using namespace std;

class CClock
{
private://private表示只能类内访问
	char* m_From;
	int m_Hour;
	int m_Minute;
	int m_Second;
public://表示类内与类外都都可访问,还有protect权限与继承有关,在后面的博客
	
	CClock();//此处重写了构造函数中的默认构造函数,如果后面直接写=default表示使用默认的构造函数,自己不用写;如果是=delete表示不使用该构造函数
	CClock(int a);//含有一个参数的构造函数,该函数既表示构造函数,又表示一种隐式转换,从而还可以这样调用CClock obj=1;
	CClock(int n, int k);//看看实现当中如何用参数列表书写构造函数
	CClock(int a, int b, int c);//含有三个参数的构造函数
	CClock(char* s, int a, int b, int c);//看该构造函数的实现,里面有动态申请的内存,所以要特别注意析构函数要注意释放。
	CClock(CClock& obj);//重写拷贝构造函数为深拷贝

	
	void getTime();
	void setClock(char* s,int a,int b,int c);

	
	~CClock();
};
CClock::CClock(){
	cout << "调用了CClock()构造函数" << endl;
	m_From = nullptr;
}
CClock::CClock(int a)
{
	cout << "调用了CClock(int a)构造函数" << endl;
	m_Hour = a;
	m_From = nullptr;
}
CClock::CClock(int n, int k) : m_Hour(n), m_Minute(k) {
	cout << "调用了CClock(int n, int k)构造函数" << endl;
	m_From = nullptr;
}
CClock::CClock(int a, int b, int c)
{
	cout << "调用了CClock(int a, int b, int c)构造函数" << endl;
	if ((a < 0 || a >= 24) || (b < 0 || b >= 60) || (c < 0 || c >= 60))
		return;
	else
	{
		m_Hour = a;
		m_Minute = b;
		m_Second = c;
		m_From = nullptr;
	}
}
CClock::CClock(char* s, int a, int b, int c)
{
	cout << "调用了CClock(char* s, int a, int b, int c)构造函数" << endl;
	m_From = new char[255];//类内部动态申请了堆资源,析构函数中注意释放
	strcpy(m_From, s);
	m_Hour = a;
	m_Minute = b;
	m_Second = c;
}
CClock::CClock(CClock& obj)
{
	cout << "调用了CClock(CClock& obj)拷贝构造函数" << endl;
	m_From= new char[255];
	strcpy(m_From, obj.m_From);
	m_Hour = obj.m_Hour;
	m_Minute = obj.m_Minute;
	m_Second = obj.m_Second;
}
CClock::~CClock()
{
	if (m_From != nullptr)
	{
		delete[] m_From;
		cout << "析构并释放堆资源" << endl;
	}
	else
	{
		cout << "析构" << endl;
	}
		
}
void CClock::getTime()//成员函数getTime()的实现
{
	if(m_From!=nullptr)
	    cout <<"该表产自于"<("上海"), 0,0,0);//调用CClock(char* s, int a, int b, int c);构造函数,该构造函数内部申请了堆资源,因此要特别注意析构函数的书写
	CClock watche5(watche4);
	watche4.getTime();
	watche5.getTime();
	watche0.getTime();
	//栈对象在声明的时候自动构造,在出块作用域以后自动析构


	
	CClock* Pwatch0 = new CClock;
	CClock* Pwatche1 = new CClock(1);
	CClock* Pwatche2 = new CClock(1, 2);//调用(int n, int k);构造函数
	CClock* Pwatche3 = new CClock(1, 2, 3);//调用CClock(int a, int b, int c);构造函数
	CClock* Pwatche4 = new CClock(const_cast("上海"), 0, 0, 0);//调用CClock(char* s, int a, int b, int c);构造函数,该构造函数内部申请了堆资源,因此要特别注意析构函数的书写
	Pwatche4->getTime();
	delete Pwatch0;
	delete Pwatche1;
	delete Pwatche2;
	delete Pwatche3;
	delete Pwatche4;//new与delete要搭配使用,new会调用构造函数,delete会调用析构函数,注意不是自动调用析构,而是通过delete调用

	
	CClock* P = new CClock[10];
	delete[] P;

	
	CClock** PP=new CClock*[10];
	for (int i = 0; i < 10; i++)
		PP[i] = new CClock(1);//创建堆对象数组
	for (int i = 0; i < 10; i++)
		delete PP[i];//释放堆对象数组
	delete[] PP;

}

需要注意的是:
一,同一个类的对象,其成员函数地址是一样的,表示同一个类的对象的成员函数是共用的,即:
(1)数据是独立的。
(2)成员的函数是共用的.
成员函数调用时会愉愉的传递this指针(this指针指向本对象),通过寄存器ecx传递,这种传递方式称之为thiscall,这的话虽然类的每个对象都用的是同一个函数,但是却会分别 *** 作自己的对象,例如上例中的sh1.setHour(1)与sh2.setHour(2),他们调用的都是同一个函数,甚至函数地址都是一样的,但在调用过程中偷偷传递了this指针,最后分别更改了sh1对象与sh2对象的m_Hour。
二,程序中只提到栈上的局部对象在声明该对象时构造,在出其块作用域时自动析构。没有提到全局对象在进入main函数之前构造,在出main函数之后析构。
三,使用new和delete时注意,new和delete搭配,new []和delete[]要搭配使用。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5693698.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存