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++; } }
运行结果
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律