VScode 学习c++的一些笔记(持续更新)(后期用的vs2019)

您所在的位置:网站首页 vscode做笔记 VScode 学习c++的一些笔记(持续更新)(后期用的vs2019)

VScode 学习c++的一些笔记(持续更新)(后期用的vs2019)

#VScode 学习c++的一些笔记(持续更新)(后期用的vs2019)| 来源: 网络整理| 查看: 265

VScode 学习c++的一些笔记(持续更新) 1.文件夹

文件夹以及里面所有的文件的名字都不能含中文。

2.返回值优化

在学拷贝构造函数调用时机的第三种情况:以值方式返回局部对象时出现了和老师不一样的结果。

#include using namespace std; #include #include class Person { public: Person() { cout cout Person man(100); //p对象已经创建完毕 Person newman(man); //调用拷贝构造函数 Person newman2 = man; //拷贝构造 // Person newman3; // newman3 = man; //不是调用拷贝构造函数,赋值操作 } //2. 值传递的方式给函数参数传值 //相当于Person p1 = p; void doWork(Person p1) {} void test02() { Person p; //无参构造函数 doWork(p); } //3. 以值方式返回局部对象 Person doWork2() { Person p1; cout // test01(); //test02(); test03();//为什么输出没有拷贝函数的调用 system("pause"); return 0; }

老师的结果调用了拷贝函数,而我的vscode结果如下 在这里插入图片描述 可以发现并没有调用拷贝构造函数,经百度发现是返回值优化造成的。

参考:C++中的返回值优化(RVO)

3.关于引用

引用相当于常量指针,指向不可以更改,内容可以更改,但是加入const后变成常量引用后只具有可读性。

int &ref=a;//ref和a指向同一块地址 ref=20//编译器会自动解引用,*ref=20,虽然可读性变差,但是优化了程序

如果返回值是引用,返回值就是本身;如果返回值是一个值,实际上返回的是一个值的副本 例: 下面代码是一个类的成员函数,前置递增运算符重载,这是加了引用的函数

MyInteger& operator++() { //先++ m_Num++; //再返回 return *this; }

主函数里面输入:

MyInteger myInt; cout //先++ m_Num++; //再返回 return *this; }

主函数里面:

void test01() { MyInteger myInt; cout delete m_height; m_height=NULL;//防止野指针出现,做一个置空的操作 } }

关于深拷贝与浅拷贝的整块代码见下:

#include using namespace std; #include #include class Person { public: //无参(默认)构造函数 Person() { cout cout delete m_height; m_height=NULL;//防止野指针出现,做一个置空的操作 } } public: int m_age; int* m_height; }; void test01() { Person p1(18, 180); Person p2(p1); cout public: static int m_A; //静态成员变量 //静态成员变量特点: //1 在编译阶段分配内存 //2 类内声明,类外初始化 //3 所有对象共享同一份数据 private: static int m_B; //静态成员变量也是有访问权限的 }; int Person::m_A = 10; int Person::m_B = 10; void test01() { //静态成员变量两种访问方式 //1、通过对象 Person p1; p1.m_A = 100; cout public: Person() { mA = 0; } //非静态成员变量占对象空间 int mA; //静态成员变量不占对象空间 static int mB; //函数也不占对象空间,所有函数共享一个函数实例 void func() { cout cout //1、当形参和成员变量同名时,可用this指针来区分 this->age = age; } Person& PersonAddPerson(Person p)//这里如果用指针返回的是地址,不是返回对象; { this->age += p.age; //返回对象本身 return *this; } int age; }; void test01() { Person p1(10); cout this->age += p.age; //返回对象本身 return *this; }

如果这里去掉&的话变成了值的方式返回,本体创建了一个新的数据调用了拷贝构造函数,按照自身拷贝了一个新的值做了一个返回值,跟本体不一样了。 在这里插入图片描述

7.左移运算符重载 #include using namespace std; #include #include class Person { friend ostream& operator //} private: int m_A; int m_B; }; //全局函数实现左移重载 //ostream对象只能有一个 ostream& operator Person p1(10, 20); cout //先++ m_Num++; //再返回 return *this; } //后置++ MyInteger operator++(int) { //先返回 MyInteger temp = *this; //记录当前本身的值,然后让本身的值加1,但是返回的是以前的值,达到先返回后++; m_Num++; return temp; }

后置递增返回的是一个局部的对象,局部对象在当前函数执行完之后这个对象就被释放掉了,所以如果还要返回它的引用的话就是非法操作了 前置递增和后置递增完整版代码:

#include using namespace std; #include #include class MyInteger { friend ostream& operator //先++ m_Num++; //再返回 return *this; } //后置++ MyInteger operator++(int) { //先返回 MyInteger temp = *this; //记录当前本身的值,然后让本身的值加1,但是返回的是以前的值,达到先返回后++; m_Num++; return temp; } private: int m_Num; }; ostream& operator MyInteger myInt; cout //test01(); test02(); system("pause"); return 0; }

发现一个有趣的现象:当像完整版代码里面那样连续进行两次后置递增后输出结果为: 0 1 请按任意键继续. . . 发现只进行了一次后置递增,原因就是代码里面后置递增是值引用,返回的是一个副本,而不是原来的那个对象了,所以第一次返回的那个值是0,0再利用这个函数再返回一次还是0。 但是前置递增因为是引用返回,所以可以进行连续的递增,结果正常。

自己写的一个前置递减与后置递减函数如下:

#include using namespace std; #include #include class person { public: int p_a=3; public: person(){ cout person temp=*this; p_a--; return temp; } ~person(){ cout person p1; // --(--p1); (p1--)--; cout //将年龄数据开辟到堆区 m_Age = new int(age); } //重载赋值运算符 Person& operator=(Person &p) { if (m_Age != NULL) { delete m_Age; m_Age = NULL; } //编译器提供的代码是浅拷贝 //m_Age = p.m_Age; //提供深拷贝 解决浅拷贝的问题 m_Age = new int(*p.m_Age); //返回自身 return *this; } ~Person() { if (m_Age != NULL) { delete m_Age; m_Age = NULL; } } //年龄的指针 int *m_Age; }; void test01() { Person p1(18); Person p2(20); //Person p3(30); p2 = p1; //赋值操作 cout if (m_Age != NULL) { delete m_Age; m_Age = NULL; } //编译器提供的代码是浅拷贝 //m_Age = p.m_Age; //提供深拷贝 解决浅拷贝的问题 m_Age = new int(*p.m_Age); //返回自身 return *this; } 10.菱形继承 class Animal { public: int m_Age; }; //继承前加virtual关键字后,变为虚继承 //此时公共的父类Animal称为虚基类 class Sheep : virtual public Animal {}; class Tuo : virtual public Animal {}; class SheepTuo : public Sheep, public Tuo {}; void test01() { SheepTuo st; st.Sheep::m_Age = 100; st.Tuo::m_Age = 200; cout public: //Speak函数就是虚函数 //函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。 virtual void speak() { cout cout cout Cat cat; DoSpeak(cat); Dog dog; DoSpeak(dog); } int main() { test01(); system("pause"); return 0; } 12.多态-虚析构和纯虚析构

当子类中有在堆区开辟数据时,需要在子类析构函数中释放内存,不然会造成内存泄漏,但是在使用多态时,父类指针或引用指向子类对象,在调用析构函数时只会调用父类的析构函数,不会调用子类的析构函数。在父类中加上加上虚析构和纯虚析构后可以解决在子类中调不到子类析构的问题。

纯虚析构在类内定义,在类外声明 虚析构可以实例化对象,纯虚析构不可以实例化对象

虚析构语法:

virtual ~类名(){}

纯虚析构语法:

virtual ~类名() = 0;

类名::~类名(){}

class Animal { public: Animal() { cout cout cout cout Animal *animal = new Cat("Tom"); animal->Speak(); //通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄漏 //怎么解决?给基类增加一个虚析构函数 //虚析构函数就是用来解决通过父类指针释放子类对象 delete animal; } int main() { test01(); system("pause"); return 0; }

后面记录的均是用的VS2019

13.写文件时想要不覆盖原有文件内容时,可以写成以下内容:

ofstream ofs; ofs.open(FILENAME, ios::out|ios::app);//加ios::app在写入文件时不会覆盖原有内容

14.关于容器的改变排序规则 在用VS2019时,自定义规则函数一定要加const,不然会出错

//改变排序规则——由大到小 class MyCompare { public: bool operator()(int v1, int v2)const { return v1 > v2; } };


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3