C++语言学习笔记7

宏及pragma once解决头文件重复包含

//6-2-1.cpp

#include <iostream>
using namespace std;
#include "AA.h"
#include "BB.h"

int main(){
	CAA aa;	//报错:class类型CAA重定义
			//原因:头文件6-2-1.h引入了两遍
			//解决方式:ifndef define endif(利用宏解决头文件重复包含的问题)
			//宏的缺点:	1.一般宏用的都是文件名而文件名可能会重,将会导致部分头文件引入失败内容被屏蔽
			//			2.内核是一个判断,所以多文件多判断情况下效率并不高
			//解决方式2:pragma once(直接告诉编译器,当前文件只包含一次)
	CBB bb;

	system("pause");
	return 0;
}
//AA.h

//#ifndef __AA_H__
//#define __AA_H__ 

#pragma once

class CAA
{
public:
protected:
private:
};

//#endif
//BB.h

//#ifndef __BB_H__
//#define __BB_H__

#pragma once

#include "AA.h"

class CBB
{
public:
	CAA m_a;
protected:
private:
};

//#endif

宏、“/”、“#”、“##”的作用

//6-2-2.cpp

#include <iostream>
using namespace std;
#include "6-2-2.h"
#include "test.h"

//	宏:替换,在编译前就完成了替换工作

int main() {
	
	//for (int i = 0; i < N; i++) 
	//{
	//	cout << i << endl;
	//}

	AA(8)

	cout << 2 << endl;	//此句子的2为重载操作符函数的参数
						//此句将把2这个参数赋到对应函数参数int类型去
	BB(2)				//此句却是跳转赋到字符串类型去了,因此#的作用是将参数转换为字符串
	BB("2")				//把"2"这个当作整体作为字符串输出了

	CC(CTest1)
	CC(CTest2)

	system("pause");
	return 0;
}
//6-2-2.h

#pragma once

#define N 10

#define AA(PARAM) \
for (int i = 0; i < PARAM; i++) \
{ \
cout << i << endl; \
}

//	\ 在宏中的作用是用来连接下一行,最后一行通常不用加,该连接符\后不可以有任何东西(空格 注释 任何内容都不可以)


//  # : 将参数转换为字符串

#define BB(PARAM) \
	cout<<#PARAM<<endl;

//  ##: 连接符用于以下情况(一段代码要用多次仅改变少数部分)

#define CC(THIS_CLASS)\
	THIS_CLASS tst##THIS_CLASS;\
	tst##THIS_CLASS.show();
// CTest1 tst1;
// tst1.show();
//test.h

#pragma once
#include <iostream>
using namespace std;

class CTest1 {
public:
	void show() {
		cout << "CTest1::show" << endl;
	}
};

class CTest2 {
public:
	void show() {
		cout << "CTest2::show" << endl;
	}
};

重载操作符之类内重载

#include <iostream>
using namespace std;


//重载操作符:
//本质上是函数,告诉编译器遇到这个操作符时去调用对应函数来执行操作符的功能,一般需要有返回值,方便和后续操作符继续操作,例56行

//类内重载:一般情况下对象在操作符左边,代表用这个对象去调用操作符函数

class CTest
{
public:
	int m_a;
	CTest() {
		m_a = 10;
	}

	//void operator+(int a) {
	//	m_a + a;
	//}
	//tst + 10;		重载+这个符号
	//类内重载,有一个默认的隐藏参数this,对应tst,后面还需要一个int类型的参数对应10
	//注意:也就是说后面用+重载操作符时,使用顺序要和参数匹配,tst和int的顺序不可以调换

	int operator+(int a) {
		return m_a + a;
	}

	int operator=(int a) {
		this->m_a = a;
		return m_a;
	}

	int operator+=(int a) {
		this->m_a += a;
		return m_a;
	}

	int operator++() {	//左++,先加后返回
		return ++this->m_a;
	}

	int operator++(int) {	//右++,返回+之前的
		return this->m_a++;
	}

protected:
private:
};

int main() {
	CTest tst;
	CTest tst1;
	tst + 10;	//	CTest类型和int类型,类型不匹配无法相加。
				//	实际此处想进行的操作是将m_a+10,那么此处可以用到重载操作符
	int a = tst1 + (tst + 10);	//tst+10不是int类型而是一个void,也就是说需要给上面+的重载操作符函数(18-20行被注释部分)设置返回值

	cout << a << endl;

	CTest tst2;
	tst2 = tst1 + (tst + 10);   // =操作符也需要重载,才能完成给tst2这个类赋值为30的操作
	cout << tst2.m_a << endl;

	//除了使用+和=去调用,也可以手动去调用函数,如下:
	//tst1.operator+(12);

	CTest tst3;
	tst3 = tst1.operator+(12);
	cout << tst3.m_a << endl;

	CTest tst4;
	CTest tst5;
	tst5 = tst4 += 20;
	cout << tst4.m_a << endl;	
	cout << tst5.m_a << endl;

	CTest tst6;
	CTest tst7;
	tst7 = ++tst6;
	cout << tst7.m_a << endl;

	CTest tst8;
	CTest tst9;
	tst9 = tst8++;
	cout << tst9.m_a << endl;//右++是返回+之前的,所以是10

	system("pause");
	return 0;
}

重载操作符之类外重载

//类外重载:需要注意与类内重载的冲突问题

//tst + 10可以使用类内重载,但如果是10 + tst,那么由于类内函数this默认指针居第一位,所以类内重载无法完成,此时便需要类外重载了

class CTest
{
public:
	int m_a;
	CTest() {
		m_a = 10;
	}
};

int operator+(int a, CTest& tst) {
	return a + tst.m_a;
}

//int operator+(CTest& tst, int a) {
//	return a + tst.m_a;
//}	

//	如果类内类外都其设置了重载函数,那么main中用到对应重载符时会报错:“多个运算符+与这些操作数匹配”,也就是说多个重载函数都符合要求,系统不知道应该调用哪个,此时需要仅保留一个,将其他的删除即可

int operator++(CTest& tst) {	//左++,先加后返回
	return ++tst.m_a;
	}

int operator++(CTest& tst,int) {	//右++,返回+之前的值
	return tst.m_a++;
}

ostream& operator<<(ostream& os, CTest& tst) {
	os << tst.m_a;
	return os;
}	//输出

istream& operator>>(istream& is, CTest& tst) {
	is >> tst.m_a;
	return is;
}	//输入

int main() {
	CTest tst;
	int a = 10 + tst;
	cout << a << endl;

	cout << ++tst.m_a << endl;
	cout << tst.m_a++ << endl;

	cout << tst << endl;	
	//<<也是重载符,但是其重载的是int类型,本句是CTest类型所以会报错,那么自己可以手动写一个能重载输出CTest类型的操作符
	//cout是ostream类型的,所以重载函数应该具备两个参数,一个是ostream,一个是CTest类型的,同时应该使用类外重载,因为类内的重载函数需要拿对象来调用,而此处使用cout进行调用

	cin >> tst;
	cout << tst << endl;

	system("pause");
	return 0;
}

//重载操作符函数:
//不可以改变原有操作符使用方法;
// //例如:+是a+b,左右各一个参数,因此重载操作符函数中参数的设定就只可以有两个,如果有隐藏的this指针作为参数,那么参数设定就只能再有一个(例18-20行)
//参数不能指定默认值;
// //例如:int operator+(int a = 10)
//也不可以改变优先级和结合性;

迭代器概念引入(改造遍历链表~)

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

// 迭代器
class CMyIterator {
public:
	Node* pTemp;
public:
	CMyIterator() {
		pTemp = NULL;
	}
	CMyIterator(Node* pH) {
		pTemp = pH;
	}
public:
	bool operator==(Node* pNode) {
		return pTemp == pNode ? true : false;
	}
	bool operator!=(Node* pNode) {
		return pTemp != pNode ? true : false;
	}
	Node* operator=(Node* pNode) {
		pTemp = pNode;
		return pTemp;
	}
	int operator*() {
		if (pTemp) {
			return pTemp->val;
		}
		return -1;
	}
	Node* operator++() {		//左++
		pTemp = pTemp->pNext;
		return pTemp;
	}
	Node* operator++(int) {		//右++
		Node* pT = pTemp;
		pTemp = pTemp->pNext;
		return pT;
	}
};

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;
		//	//Node* pTemp = NULL;
		//	//pTemp = m_pHead;
		//while (pTemp) {
		//	cout << pTemp->val << "	";
		//	pTemp = pTemp->pNext;
		//}

		CMyIterator ite;
		ite = m_pHead;
		//CMyIterator ite = m_pHead;	//ye
        
		while (ite != NULL) {
			cout << *ite << "   ";
			++ite;	//此处用左++或者右++都一样,因为没有用到函数返回值
					//如果是int a = ++ite或者int a = ite++则不同,是把不同的返回值赋值给了a,但ite的值都是+1了
		}
		cout << endl;
	}
};


int main() {
	MyList lst;

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

	lst.show();

	system("pause");
	return 0;
}

list及algorithm头文件

#include <iostream>
#include <list>
#include <algorithm>
using namespace std;

void Show(int a) {
	cout << a << "	";
}	//for_each 函数的第三个参数的函数

int main() {
	list<int> lst;		//定义一个链表	
	lst.push_back(1);
	lst.push_back(2);
	lst.push_back(3);	//尾添加,注意类型要和定义链表< >内的类型一致

	lst.push_front(0);	//头添加
	lst.push_front(-1);
	lst.push_front(-2);


	//链表的两种遍历方式

	//定义迭代器
	list<int>::iterator ite = lst.begin();
	//iterator 本质上也是一个类,可以当作指针用
	//lst.begin() 返回头节点,此句为返回头节点的迭代器

	while (ite != lst.end())	//循环遍历链表
	{
		cout << *ite << endl;
		ite++;
	}
	
	//引入头文件algorithm,利用::for_each函数
	::for_each(lst.begin(), lst.end(), &Show);
	cout << endl;
	//::for_each 这个函数只负责遍历,其第三个参数的函数才是进行实际操作的(想干啥自己写就行)
	//第三个参数函数的返回值及函数名无要求,但其参数有要求,参数必须为一个且为返回链表中每一个节点的元素,也就是必须和链表类型相匹配

	lst.pop_back();		//尾删除
	::for_each(lst.begin(), lst.end(), &Show);
	cout << endl;

	lst.pop_front();	//头删除
	::for_each(lst.begin(), lst.end(), &Show);
	cout << endl;

	list<int>::iterator ite1 = ++lst.begin();	//头的下一个,也就是第二个
	list<int>::iterator ite2 = lst.insert(ite1, 5);
	//lst.insert(ite1, 5);	//指定位置插入
							//第一个参数为指向插入位置的迭代器,第二个为插入的内容
							//将插入到迭代器位置之前,也就是插入内容将被放置在迭代器位置上
							//返回新插入的节点的迭代器
	::for_each(lst.begin(), lst.end(), &Show);
	cout << endl;
	cout << *ite2 << endl;

	//lst.erase(ite2);	//指定位置删除,其参数为删除位置的迭代器
	//::for_each(lst.begin(), lst.end(), &Show);
	//cout << endl;
	//cout << *ite2 << endl;	//程序崩溃,删除了该迭代器指向的节点后,该迭代器还是会指向原来那份空间,但那份空间已经被回收了,因此非法访问。
	//erase返回值返回的是当前节点的下一个节点,所以解决上述问题的方式是拿迭代器接一下就行啦,如下:
	ite2 = lst.erase(ite2);
	::for_each(lst.begin(), lst.end(), &Show);
	cout << endl;
	cout << *ite2 << endl;

	cout << lst.front() << endl;
	// begin返回的是头节点的迭代器,front是直接返回头节点的内容,该句等同于:
	list<int>::iterator ite3 = lst.begin();
	cout << *ite3 <<endl;

	cout << lst.back() << endl;	// 同理于front,back是直接返回尾节点的内容
	//list<int>::iterator ite4 = lst.end();	//程序崩溃,end所返回的并不是尾节点,而是结尾标志,也就是尾节点的下一个
	list<int>::iterator ite4 = lst.end();
	--ite4;
	cout << *ite4 << endl;

	//::find(lst.begin(), lst.end(), 3);//三个参数:从哪个范围找,找哪个值
									  //返回值是找到节点的迭代器
	//list<int>::iterator ite5 = ::find(lst.begin(), lst.end(), 3);
	//cout << *ite5 << endl;	//程序崩溃,因为没有3,没有找到,所以迭代器返回的是这个区间内的最后一个,也就是end,结尾标志,尾节点的下一个,因此会崩溃

	list<int>::iterator ite5 = ::find(lst.begin(), lst.end(), 1);
	cout << *ite5 << endl;

	system("pause");
	return 0;
}

#include <iostream>
#include <list>
#include <algorithm>
using namespace std;

struct Node
{
	int m_a;
	int m_b;
	Node() {
		m_a = 10;
		m_b = 20;
	}
};	//尽量不要值传递,最好通过引用和地址

void Show(Node* p) {
	cout << p->m_a << "	" << p->m_b << "	";
}

int main() {

	list<Node*> lst1;
	Node* p1 = new Node;
	lst1.push_back(p1);

	Node* p2 = new Node;
	p2->m_a = 30;
	p2->m_b = 40;
	lst1.push_back(p2);

	list<Node*>::iterator ite = lst1.begin();
	while (ite != lst1.end()) 
	{
		cout << (*ite)->m_a << "	" << (*ite)->m_b << "	";
		ite++;
	}
	cout << endl;

	::for_each(lst1.begin(), lst1.end(), &Show);
	cout << endl;

	system("pause");
	return 0;
}

//自己定义的复杂类型也可以使用list及algorithm噢
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

97Marcus

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

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

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

打赏作者

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

抵扣说明:

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

余额充值