张德长

导航

C++学习笔记(2)

C++学习笔记(2)

 

 

思维导图

浅拷贝和深拷贝:

  • 浅拷贝:简单的赋值拷贝;
  • 深拷贝:在堆区重新申请空间,进行拷贝;
  • 浅拷贝的问题:堆区内存重复释放;
  • 可以利用深拷贝解决这个问题;

深拷贝构造函数

//深拷贝的测试
class Person2
{
public :
	int mAge;
	int* mHeight;
	Person2() 
	{
		mAge = 0; 
		mHeight = 0;
		cout << "无参构造的调用" << endl;
	}
	Person2(int age,int height)
	{
		cout << "有参构造的调用" << endl;
		mAge = age;
		mHeight = new int(height);
		
	}
	Person2(const Person2 & p)
	{
		cout << "深拷贝构造的调用" << endl;
		this->mAge = p.mAge;
		//this->mHeight = p.mHeight;//默认拷贝构造的代码,执行 浅拷贝
		this->mHeight = new int(*p.mHeight);//自定义深拷贝
	}
	~Person2()
	{
		cout << "析构函数的调用" << endl;
		if (mHeight != NULL)delete mHeight;//释放堆内存
		mHeight = NULL;//将指针成员变量置空,防止野指针
	}
};
void test12()
{
	Person2 p1(22,150);
	cout << "p1.mAge=" << p1.mAge << "	*p1.mHeight=" << *p1.mHeight << "	(int)p1.mHeight=" << (int)p1.mHeight << endl;
	Person2 p2(p1);
	cout << "p2.mAge=" << p2.mAge << "	*p2.mHeight=" << *p2.mHeight << "	(int)p2.mHeight=" << (int)p2.mHeight << endl;
}

int main()
{
	test12();
	system("pause");
	return 1;
}

运行结果

 

拷贝构造使用时机:

  • 使用一个已经创建好的对象创建一个新对象;Person p2(p1);
  • 值传递的方式给函数参数传值;void doWork(Person p){};
  • 以值的方式返回局部对象;Person func(){Person p;return p;}

以值方式传递参数和返回对象,都会创建一个副本,也就是拷贝构造;

//构造函数 析构函数
class Person
{
public:
	int age;
	Person() { this->age = 0; };//无参构造
	Person(int age) { this->age = age; };//有参构造
	Person(const Person& p) { this->age = p.age; };//拷贝构造
	~Person() {};//析构函数
};

//值传递的方式传参
void doWork(Person p4)
{
	cout << "(int)&p4=" << (int)&p4 << "	p4.age=" << p4.age << endl;
}
//值方式返回一个对象
Person doWork()
{
	Person p5 = 55;
	cout << "(int)&p5=" << (int)&p5 << "	p5.age=" << p5.age << endl;
	return p5;
}
//拷贝构造调用时机
void test11()
{
	//从一个已有的对象创建一个新的对象
	Person p1=11;
	Person p2(p1);
	cout << "(int)&p1=" << (int)&p1 << "	p1.age=" << p1.age << endl;
	cout << "(int)&p2=" << (int)&p2 << "	p2.age=" << p2.age << endl;
	//值传递的方式,将对象作为参数进行传递
	Person p3 = 33;
	cout << "(int)&p3=" << (int)&p3 << "	p3.age=" << p3.age << endl;
	doWork(p3);
	//值传递的方式,返回一个对象
	Person p6 = doWork();
	cout << "(int)&p6=" << (int)&p6 << "	p6.age=" << p6.age << endl;
}

运行结果

三类构造函数:无参构造、有参构造、拷贝构造;无参构造和有参构造统称为普通构造;

三类调用方式:括号法,显示法,隐式转换法;

//构造函数
class Person
{
public:
	int age;
	Person() { this->age = 0; };//无参构造
	Person(int age) { this->age = age; };//有参构造
	Person(const Person& p) { this->age = p.age; };//拷贝构造

};
void test10()
{
	//一、括号法
	Person p1;
	Person p2(10);
	Person p3(p2);
	//二、显示法
	Person p4 = Person();
	Person p5 = Person(20);
	Person p6 = Person(p5);
	//三、隐式转换法
	Person p7 = 30;
	Person p8 = p7;
	cout << "p1.age=" << p1.age << endl;
	cout << "p2.age=" << p2.age << endl;
	cout << "p3.age=" << p3.age << endl;
	cout << "p4.age=" << p4.age << endl;
	cout << "p5.age=" << p5.age << endl;
	cout << "p6.age=" << p6.age << endl;
	cout << "p7.age=" << p7.age << endl;
	cout << "p8.age=" << p8.age << endl;
}

运行结果

仿函数(函数对象)测试
仿函数的本质并不是函数,而是重载了operator()的类;
1、仿函数可以像普通函数那样进行调用,可以有参数和返回值;
2、仿函数超越普通函数的概念,可以拥有自己的状态(属性)
3、仿函数可以作为函数的参数进行传递

//仿函数(函数对象)测试
//仿函数的本质并不是函数,而是重载了operator()的类;
//1、仿函数可以像普通函数那样进行调用,可以有参数和返回值;
//2、仿函数超越普通函数的概念,可以拥有自己的状态(属性)
//3、仿函数可以作为函数的参数进行传递

//有参数和返回值的仿函数
class Add
{
public:
	int operator()(int a, int b)const
	{
		return a + b;
	}
};
//有状态(属性)的仿函数
class MyPrint
{
public:
	int count;
	MyPrint()
	{
		this->count = 0;
	}
	void operator()(string s)
	{
		cout << s << endl;
		count++;
	}
};
//作为参数传递的仿函数
void doPrint(MyPrint &print,string s)
{
	print(s);
}
void test9()
{
	Add add;
	cout<<"有参数和返回值的仿函数add(5, 8)=" << add(5, 8) << endl<<endl;
	
	MyPrint print;
	for (size_t i = 0; i < 5; i++)
	{
		print("我是有状态的 仿函数!");
		cout << "仿函数调用的次数=" << print.count << endl;
	}
	cout << endl;
	string s = "仿函数作为参数进行传递!";
	doPrint(print,s);
}

运行结果

C++的8种容器类的要点总结

置物之所也;

数组、链表、树、栈、队列、结合、映射表;

序列式容器:强调值的顺序,每个元素都有固定的位置;

关联式容器:二叉树,元素之间没有固定的物理顺序;

一、string字符串类compare,substr,insert,assign,=,append,+=,at,[ ],

二、vector单端数组push_back,pop_back,insert,size,capacity,resize,empty

,erase,clear,at,[ ],front,back,swap交换,收缩容量vector<int>(v).swap(v);,

reserve预留空间,

三、deque双端数组/中控器,push_front,pop_front,push_back,pop_back,

insert,begin,end,front,back,=,assign,empty,size,resize,insert,erase,clear,

at,[ ],sort,

四、stack栈容器,只有一个出入口,先进后出,栈底,栈顶top,入栈push,出栈pop,empty,size,=,不允许遍历,

五、queue队列,先进先出,一端为出口,一端为入口,不允许遍历,push,pop,front,back,empty,size,

六、list链表,内存不连续,由一系列节点组成(数据域+指针域),双向循环链表,

push_front,pop_front,push_back,pop_back,front,back,begin,end,prev,next,

assign,=,swap,empty,size,resize,inset,erase,clear,remove,

不支持(at,[ ]),不支持随机访问,reverse,sort,

  • 可以快速对任意位置插入/删除元素,而无需移动其他元素;
  • 动态分配内存,不会造成内存浪费和溢出;
  • 空间(指针域)时间(遍历)的额外耗费比较大;
  • 插入和删除操作不会造成原迭代器的失效,这在vector中不成立;

七、set集合multiset,属于关联式结构,二叉树,所有元素插入时自动排序,

set不允许有重复元素,multiset允许重复元素;

empty,size,swap,insert,erase,clear,find(返回迭代器或end),count(重复元素的个数),set插入会返回插入结果(成功或失败=重复或不重复),,

不支持(头插,头删,尾插,尾删,resize),sort,

仿函数=函数重载/运算符重载;

默认排序从小到大,可以利用仿函数改变排序规则(重载小括号())

pair对组,默认构造,make_pair,,,,,

八、map容器,所有元素都是pair,第一个元素称为key,第二个元素称为value;

所有元素都会按照键值自动排序,本质是一个关联式容器,底层实现是二叉树;

优点:快速按照key查找元素,map不允许重复key,multimap允许重复key;

默认构造、拷贝构造、=,empty,size,swap,insert,erase,clear,

find按照key查找,返回迭代器或者end,count统计key的个数;

默认排序从小到大,可以利用仿函数改变排序规则(重载小括号())

利用仿函数重新定义排序规则

//利用仿函数重新定义排序规则
#include<set>
//输出set容器内容,重载一
void printSet(const  set<int>& s)
{
	//遍历set容器并输出
	for (set<int>::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << " " << *it;
	}
	cout << endl;
}
//仿函数,重新定义set集合的排序规则(从大到小)
class MyCompare
{
public:
	bool operator ()(int a, int b)const
	{
		return a > b;
	}
};
//输出set容器内容,重载二
void printSet(const  set<int, MyCompare>& s)
{
	//遍历set容器并输出
	for (set<int, MyCompare>::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << " " << *it;
	}
	cout << endl;
}

void test8()
{
	//定义一个从小到大排序的set容器
	set<int> set1;
	for (size_t i = 0; i < 10; i++)
	{
		set1.insert(i);
	}
	printSet(set1);
	//使用仿函数,定义一个从大到小排序的set容器
	set<int, MyCompare>set2;
	set2.insert(1);
	for (size_t i = 0; i < 10; i++)
	{
		set2.insert(i);
	}
	printSet(set2);
}

运行结果

vector的四种遍历方法测试

//迭代器测试iterator
void myPrint(int a)
{
	cout <<&a<<"	=	" << a << endl;
}

void test6()
{
	vector<int> v;
	v.push_back(11);
	v.push_back(22);
	v.push_back(33);
	v.push_back(44);
	v.push_back(55);
	//方法一
	cout << "---------方法一----------------" << endl;
	vector<int>::iterator begin = v.begin();
	vector<int>::iterator end = v.end();
	while (begin!=end)
	{
		cout <<"begin._Ptr="<<begin._Ptr<<"	*begin=" << *begin << endl;
		begin++;
	}
	cout << "---------方法二----------------" << endl;
	//方法二
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << "it._Ptr=" << it._Ptr << "	*it=" << *it << endl;
		
	}
	cout << "-----------方法三--------------" << endl;
	
	//方法三
	for (size_t i = 0; i < v.size(); i++)
	{
		cout << "&v[i]=" << &v[i] << "	v[i]=" << v[i] << endl;
	}
	cout << "---------方法四----------------" << endl;
	//方法四
	for_each(v.begin(), v.end(), myPrint);


}

运行结果

vector测试

//vector测试
void test7()
{
	vector<int>v;
	for (size_t i = 0; i < 100; i++)
	{
		cout << "v.size()=" << v.size() << "		v.capacity()=" << v.capacity() << "		sizeof(v)=" << sizeof(v) << endl;
		
		v.push_back(1);
	}
}

运行结果

迭代器

void test6()
{
	vector<int> v;
	v.push_back(11);
	v.push_back(22);
	v.push_back(33);
	v.push_back(44);
	v.push_back(55);
	vector<int>::iterator begin = v.begin();
	vector<int>::iterator end = v.end();
	while (begin!=end)
	{
		cout <<"begin._Ptr="<<begin._Ptr<<"	*begin=" << *begin << endl;
		begin++;
	}
}

运行结果

posted on 2022-05-15 17:01  张德长  阅读(39)  评论(0编辑  收藏  举报