C++语言学习笔记2

const

#include<iostream>
using namespace std;

//const
int main() {
	
	int a = 10;
	a = 20;
	int* p = &a;

	const int b = 20;
	//b = 10;//会报错,b为常量,一旦定义就必须初始化且之后无法再进行修改
	//int* p2 = &b;//const int类型的值不能用于初始化int类型的实体
	const int* p2 = &b;//const:不能通过指针去修改指向的空间里的值
	p2 = &a;//但可以指向别的空间
	const int* p3 = &a;
	//*p3 = 4;//const:不能通过指针去修改指向的空间里的值

	int* const p5 = &a;//p5一旦定义就必须初始化且之后无法再进行修改
	//p5 = &b;//一旦定义了指向了一个具体的空间,就不能再指向其他的空间

	system("pause");
	return 0;
}

引用

int main() {

	int a = 10;
	int& b = a;  //定义引用,b是名字,引用的类型需要和被引用的一致

	cout << b << endl;

	a = 12;

	cout << a << endl;
	cout << b << endl;

	//int& c;  //定义引用时必须初始化

	system("pause");
	return 0;
}

/*
1.定义指针可以NULL,但引用不可以为NULL,定义时必须初始化
2.有空的指针,但是没有空的引用
3.指针占用空间,引用不占用额外的空间
*/

三种传递

//值传递
void show(int a) 
{
	cout << a << endl;
}

//地址传递
void show(int* p) 
{
	cout << *p << endl;
}

//引用传递
void play(int& b) 
{
	 cout << b << endl;
	 b = 12;
}

int main(){

	int a = 10;
	show(a);	//值传递
	show(&a);	//地址传递
	play(a);	//引用传递
	cout << a << endl;

	system("pause");
	return 0;
}

链表

struct Node {
	int val;
	Node* pNext;
};

//void PushBack(Node** pH, Node** pE, int v)  
//{
//	Node* pNode = new Node;
//	pNode->val = v;
//	pNode->pNext = NULL;
//c
//	if (*pH)		 //链表不为空
//	{
//		(*pE)->pNext = pNode;
//		(*pE) = pNode;
//	} 
//	else		     //链表为空
//	{
//		(*pH) = pNode;
//		(*pE) = pNode;
//	}
//}					//可以引用,引用的类型是Node*

void PushBack(Node*& pH, Node*& pE, int v)
{
	Node* pNode = new Node;
	pNode->val = v;
	pNode->pNext = NULL;

	if (pH)		     //链表不为空
	{
		(pE)->pNext = pNode;
		(pE) = pNode;
	} 
	else		     //链表为空
	{
		(pH) = pNode;
		(pE) = pNode;
	}
}

void Show(Node* pH) 
{
	if (pH)
	{
		while (pH) 
		{
			cout << pH->val << endl;
			pH = pH->pNext;
		}
	}
}

int main() 
{
	Node* pHead = NULL;
	Node* pEnd = NULL;

	//PushBack(&pHead, &pEnd, 1);
	//PushBack(&pHead, &pEnd, 2);
	//PushBack(&pHead, &pEnd, 3);
	//PushBack(&pHead, &pEnd, 4);

	PushBack(pHead, pEnd, 1);
	PushBack(pHead, pEnd, 2);
	PushBack(pHead, pEnd, 3);
	PushBack(pHead, pEnd, 4);

	Show(pHead);

	system("pause");
	return 0;
}

类的成员变量

/*
C 数据和算法 关联性不强
C++ 将完成某一功能的数据 算法 封装起来形成一个类 关联性强

类:数据和算法的集合,是抽象的(不是具体的,不占用内存空间,只是表明是一个类)
对象:定义一个类的实例(变量),是具体的(占用内存空间)
*/

//类的成员变量

class CPeople{  //类的定义  类名一半以C开头
	int m_nAge;		//成员变量一般以m_开头
	bool m_bSex; 
	string m_strName;

	void show() {	//成员函数中可以直接使用上述变量
		cout << m_strName << endl;
		cout << m_bSex << endl;
		cout << m_nAge << endl;
	}
};


int main() {

	//CPeople people;	//定义对象
	//people.m_nAge = 10;
	//people.m_bSex = true;
	//people.m_strName = "小明";

	//报错:无法访问,因此需要访问修饰符

	system("pause");
	return 0;
}


//如果不写string的头文件,变量申明所用到string时不会报错,因为string作为关键字是存在于编译器中的,但如果变量用到了string头文件的函数,就会报错。
class CPeople{  
	string m_strName;	//不用string头文件不报错

	void show() {	
		cout << m_strName << endl;	//不用string头文件会报错
	}
};

类的访问修饰符

/*
访问修饰符:
public:公共的,类内类外都可以用
protected:保护的,类内可以,子类也可以
private:私有的,只能在类内使用
*/

class CPeople {  //类的定义  类名一半以C开头
private:
	int m_nAge;		//成员变量一般以m_开头
protected:
	bool m_bSex;
public:
	string m_strName;
	void show() {	//成员函数中可以直接使用上述变量
		cout << m_strName << endl;
		cout << m_bSex << endl;
		cout << m_nAge << endl;
	}
};


int main() {

	//CPeople people;	//定义对象  类的变量和函数都必须通过对象来用
	people.m_nAge = 10;
	people.m_bSex = true;
	//people.m_strName = "小明";
	//people.show();

	//定义对象的另一种方式
	CPeople* pPeo = new CPeople;
	pPeo->m_strName = "小李";
	pPeo->show();

	system("pause");
	return 0;
}

私有变量设置及获取值

class CPeople {  
private:
	int m_nAge;		
protected:
	bool m_bSex;
public:
	string m_strName;
	void show() {	
		cout << m_strName << endl;
		cout << m_bSex << endl;
		cout << m_nAge << endl;
	}

	//对于私有变量,可以提供一个接口(构造一个公有的函数)去设置及获取值。
	void SetAge(int age) {
		m_nAge = age;
	}
	int GetAge() {
		return m_nAge;
	}
	//如果私有变量众多,每个都要构造两个函数去设置和获取则很麻烦,所以需要构造函数,这是类中的一个特殊函数,如果类中不写,则编译器会提供一个默认的无参的构造函数(函数名是当前类名,没有返回值),如果写的话则写的作为构造函数,编译器不再提供了。
};


int main() {

	//CPeople people;	
	people.m_nAge = 10;
	people.m_bSex = true;
	//people.m_strName = "小明";
	//people.show();

	CPeople* pPeo = new CPeople;
	pPeo->m_strName = "小李";

	pPeo->SetAge(18);
	cout << pPeo->GetAge() << endl;

	pPeo->show();

	system("pause");
	return 0;
}

构造函数和析构函数

//函数名为当前类名,没有返回值,参数可以有也可以没有
//构造函数:用来初始化类成员变量,定义对象时会自动调用。可以有多个构造函数,是函数重载的关系。定义对象最终只执行某一个构造函数。
//析构函数(用于回收空间):和构造函数是对应关系,是用来释放成员申请空间的,函数名为~类名,析构函数只能有一个,析构函数无参数,无返回值。

class CTest
{
public:
	int m_nAge;
	int m_nSex;
	int* m_p;
	CTest() {//无参的构造函数
		m_nAge = 10;
		m_p = new int(10);
	}
	CTest(int age) {//有参的构造函数
		m_nAge = age;
	}
	CTest(int age, int sex)
	{
		m_nAge = age;
		m_nSex = sex;
	}
	//析构函数
	~CTest() 
	{
		cout << "~CTest" << endl;
		if (m_p) {
			delete m_p;
			m_p = NULL;
		}//对象生命周期结束时,先执行析构函数,再释放对象的栈区的空间
	}
protected:
private:
};

int main() {
	//CTest tst;//调用无参的构造函数
	//cout << tst.m_nAge << endl;

	//CTest tst2(12);//调用有参的构造函数
	//cout << tst2.m_nAge << endl;

	//CTest* pTst = new CTest(12, 1);
	//cout << pTst->m_nAge << endl;
	//cout << pTst->m_nSex << endl;

	//delete pTst; //new了就要delete 释放时会自动调用析构函数
	//pTst = NULL;
	{
		CTest tst;
	}//到括号自动释放 释放时也会自动调用析构函数

	system("pause");
	return 0;
}

练习1

封装一个CDate类:
成员属性为年、月、日
成员方法为构造、析构、显示日期(Display)、设置日期差(SetDate)…等
一个CDate对象可以用三个整数表示年、月、日(2021.3.3)来初始化,而且可以对日期的设置进行合法性校验,要求实现CDate类的成员。

class CDate {
public:
	int m_nYear;
	int m_nMonth;
	int m_nDay;
public:
	CDate() {
		m_nYear = 1970;
		m_nMonth = 1;
		m_nDay = 1;
	}
	~CDate() {
		m_nYear = 0;
		m_nMonth = 0;
		m_nDay = 0;//有指针的话必须写,没有指针可以不写,但是严格上都要写,置成当前类型的初始值
/*此为构析函数,一般用在这个类使用完之后,将类里的变量重新初始化的,不是指针的变量重新初始化只需要置为0就行,但是指针变量由于指向了一块内存空间,需要先将内存释放掉,再将指针置为NULL,f会内存泄露。所以如果类里面有指针的时候必须在构析函数里将指针的内存释放掉+指针置为空,否则会内存泄露;如果类里面没有指针的话,由于普通变量不会导致内存泄露所以写不写都行。*/
	}
public:
	void Display() {
		cout << m_nYear << "-" << m_nMonth << "-" << m_nDay << endl;
	}
	void SetDate(int year, int month, int day) {
		if (year >= 1970 && year <= 2099)
		{
			m_nYear = year;
		}
		if (month >= 1 && month <= 12)
		{
			m_nMonth = month;
		}
		if (day >= 1 && day <= 30)
		{
			m_nDay = day;
		}
	}
};

int main() {
	CDate date;

	date.Display();

	date.SetDate(2021, 5, 21); 
	
	date.Display();

	system("pause");
	return 0;
}

封装链表

C++中struct结构体和class类的区别

1.类的默认访问修饰符是私有private的 结构体的默认访问修饰符是公有public的
2.类的默认继承方式是私有privat的 结构体的默认继承方式是公有public的

struct Node {
	int val;
	Node* pNext;
	Node(int v) {
		val = v;
		pNext = NULL;
	}
};

class MyList
{
public:
	Node* m_pHead;
	Node* m_pEnd;
	int m_nLen;//链表长度 节点个数
public:
	MyList() {
		m_pHead = NULL;
		m_pEnd = NULL;
		m_nLen = 0;
	}
	~MyList() {//析构是生命周期结束了所以这里应该遍历链表删除节点
		Node* pTemp = NULL;
		while (m_pHead) {
			pTemp = m_pHead;
			m_pHead = m_pHead->pNext;
			delete pTemp;
			pTemp = NULL;
		}
		m_pHead = NULL;
		m_pEnd = NULL;
		m_nLen = 0;
	}
public:
	void PushBack(int v) {
		//Node* pTemp = new Node;//报错:没有默认的构造函数,原因是结构体中写了构造函数,因此系统不再提供默认的构造函数,而是采用写的有参的构造函数
		Node* pTemp = new Node(v);

		if (m_pHead){
			m_pEnd->pNext = pTemp;
			m_pEnd = m_pEnd->pNext;
		}
		else {
			m_pHead = pTemp;
			m_pEnd = pTemp;
		}
		m_nLen++;

	}

	void show() {
		Node* pTemp = m_pHead;
		while (pTemp) {
			cout << pTemp->val << "	";
			pTemp = pTemp->pNext;
		}
		cout << endl;
	}

	void PopFront() {//头删除
		if (m_pHead)
		{
			Node* pTemp = m_pHead;
			if (m_pHead == m_pEnd) 
			{
				//delete pTemp;
				//pTemp = NULL;
				m_pHead = NULL;
				m_pEnd = NULL;
			} 
			else
			{
				m_pHead = m_pHead->pNext;
				//delete pTemp;
				//pTemp = NULL;
			}
			delete pTemp;
			pTemp = NULL;
			m_nLen--;
		}
	}

protected:
private:
};



int main() {
	MyList lst;

	lst.PushBack(1);
	lst.PushBack(2);
	lst.PushBack(3);
	lst.PushBack(4);

	lst.show();

	lst.PopFront();
	lst.show();
	lst.PopFront();
	lst.show();	

	system("pause");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

97Marcus

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值