注:我是看视频敲的代码 视频学习链接 侵删
黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难
- c++学习笔记
- 1、基本使用
- 2、引用的本质
- 3、函数的提高
- 3.1 函数的默认参数
- 3.1 函数的占位参数
- 3.2函数的重载
- 4.类和对象
- 4.1访问权限
- 4.2 struct 和 class的区别
- 4.3成员属性私有化
- 4.4对象的初始化和清理
- 4.5构造函数的分类以及调用
- 4.3拷贝构造函数调用时机
- 4.4g构造函数调用规则
- 4.5 深拷贝与浅拷贝
- 4.6 初始化列表
- 4.7类的对象作为类的成员
- 4.8 静态成员
- 4.9c++ 对象模型和this指针
- 4.10 this 指针
- 4.11空指针调用成员函数
- 4.12 const 修饰成员函数
- 4.13友元 friend
- 4.14 运算符重载四则运算
- 4.15 左移运算符重载
- 4.16 递增运算符重载
- 4.17 匿名函数
- 5.继承
- 5.1 继承中的对象模型
- 5.2继承中的构造和析构顺序
- 5.2继承中同名成员处理
- 5.3继承静态成员函数的处理方式
- 5.4多继承语法
- 5.5 菱形继承
- 6.多态
- 6.1多态的基本概念
- 6.2 纯虚函数
- 6.3虚析构和纯虚析构
- 7文件操作
- 7.1写文件
- 7.2读文件
- 8、c++提高编程
- 8.1函数模板
- 8.2函数模板注意事项
- 8.3普通函数和函数模板的区别
- 8.4类模板和函数模板的区别
- 8.5 类模板中成员函数的创建时机
- 9.STL使用
#include2、引用的本质#include using namespace std; int *swap(int *a, int *b) { int ARR[2]; int tem = *a; *a = *b; *b = tem; ARR[0] = *a; ARR[1] = *b; return ARR; } void swap2(int &c,int &d) { int tem = c; c = d; d = tem; } // 结构体 struct MyStruct { int age; string name; }; //结构体指针--嵌套结构体 struct MyStruct2 { int age; string name; MyStruct s; }; //引用 int &小名=原名 int main() { int arr[3] = { 2,3,4 }; int a = 3; int b = 4; int *rr; MyStruct s3[3]; MyStruct2* s4=new MyStruct2[2]; MyStruct2 *ssss = new MyStruct2[12]; s4->age = 13; s3[0].age = 16; s3[0].name = "计算机"; cout << s3[0].age << "姓名" < age<< s3[0].name << endl; swap2(a, b); cout << a << "-------" << b<< endl; delete []s4;// 对应New 使用的数组 学习到引用的注意事项 //引用之前必须初始化,引用一旦初始化之后 就不可以更改引用 // 静态变量存放在全局区 static int s;存放的是全局区 }
-
引用的本质是指针常量
-
*相当于解引用,找到变量的地址
#include3、函数的提高 3.1 函数的默认参数#include using namespace std; void swap(const int &a){ a=1000;//将会报错,因为有const修饰 }
#include3.1 函数的占位参数#include using namespace std; int fun(int a,int b=10 ,int c=10) { return a + b + c; } int main() { cout << fun(10, 20, 30);//c传入参数就用传入的参数 否则就用默认的参数 // 从某个位置有了默认参数,则从左到右必须都要有 // 函数实现和声明只能一个有默认参数 }
#include3.2函数的重载#include using namespace std; int fun(int a ,int) {//第二个参数就是占位符亦可以默认参数 int a=10 return a ; } int main() { cout << fun(10, 20);//c传入参数就用传入的参数 否则就用默认的参数 // 从某个位置有了默认参数,则从左到右必须都要有 }
作用:函数名可以相同,提高复用性
满足条件:
- 同一个作用域
- 函数名称相同
- 函数参数类型不同或者个数不同或者顺序不同
注意:函数的参数不可以作为函数重载的条件
#include4.类和对象#include using namespace std; // 函数重载 void fun() { cout << "函数重载fun()" << endl; } void fun(int a ) {// 函数参数个数不同 cout << "函数重载fun(int a)" << endl; } void fun(double a) {// 函数参数类型不同 cout << "函数重载fun(double a)" << endl; } void fun(double a,int b) {// 函数参数类型不同 cout << "函数重载fun(double a,int b)" << endl; } void fun(int a, double b) {// 函数参数顺序不同 cout << "函数重载fun(int b,double a)" << endl; } void fun(const int &a) {// 函数参数顺序不同 cout << "函数重载fun(const int b,double a)" << endl; } void fun(int &a ) {// 函数参数个数不同 cout << "函数重载fun(int a)" << endl; } //int fun() { // cout << "函数返回值不可以重载fun()" << endl; //} int main() { fun(a);//调用无const fun(10);// 调用有const fun(); fun(10); fun(10, 0.1); return 0; } // 函数重载遇到默认参数时就会报错 尽量避免这种情况
#include4.1访问权限#include using namespace std; #define PI 3.14; // 类和对象 class student { public: //属性 成员属性 成员变量 string name; string num; void setName(string nnname) { name = nnname; } // 行为-方法 void getData() { cout << name << "----" << num << endl; } }; int main() { //实例化对象 student s; //s.name = "张三"; s.setName("张三"); s.num = "123321"; s.getData(); return 0; }
#include4.2 struct 和 class的区别#include using namespace std; #define PI 3.14; // 访问权限 class student { public://类内部可以访问 类外可以访问 string name; void setname(string outcar) { car = outcar; cout << "可以访问" << endl; show(outcar); } protected://类内部可以访问 类外不可以访问 string car; void show(string ccc) { cout << ccc<< endl; } private://类内部可以访问 类外不可以访问 int password; }; int main() { student s; s.setname("宝马"); //s.show();//报错 外部不可以访问 return 0; }
-
struct 默认权限 public
-
class 默认权限 private
#include4.4对象的初始化和清理#include using namespace std; #define PI 3.14; // 成员属性设置为私有 // 可以自己控制读写权限 // 对于写可以检测数据的有效性 // 写 -----set方法 读----get方法 class person { public: void setName(string nname) {//写 name = nname;//传入参数和成员变量名称尽量不一样 } void getName() {//读 cout << "姓名:" << name << endl; } void getAge() {//读 age = 0; cout << "年纪:" << age << endl; } private: string name;//可读可写 int age;//可读 string lover;//可写 }; int main() { person p; p.setName("xzs"); p.getName(); p.getAge(); //p.setAge();//年纪不可写 报错 return 0; }
- 构造函数:初始化 --主要用于创建对象时为对象成员赋值,由编译器自动调用 无需手动调用
- 析构函数:清理-对象销毁前系统自动调用,执行一些清理工作。
- 以上函数由编辑器自动调用,如果不写 编译器提供的是二者的空实现
#include4.5构造函数的分类以及调用#include using namespace std; class MyClass { public: MyClass(int a) { age = a; cout << "构造函数" << endl; } ~MyClass() { cout << "析构函数" <
-
构造函数的分类
- 1.参数类型
- 无参构造函数
- 有参构造函数
- 2.构造类型
-
普通构造函数
-
拷贝构造函数
-
- 1.参数类型
-
函数调用
- 采用括号调用 显示调用即可
#include4.3拷贝构造函数调用时机#include using namespace std; class person { public: person(int aage) { cout << "有参构造" << endl; } person() { cout << "无参构造函数" << endl; } person(const person& p) { cout << "拷贝构造函数" << endl; } public: int age; }; int main() { // 调用 person p;// 不可以写成person p(); person p2(10); person p3(p2); return 0; }
- 使用一个已经创建完毕的对象初始化一个新对象
- 值传递的方式给函数参数传值
- 以值方式返回局部对象
默认情况下。c++编译器至少给一个类添加3个函数
- 默认构造函数(无参,函数体为空)
- 默认析构函数(无参,函数体为空)
- 默认拷贝构造函数,对属性进行值拷贝
给猴枣函数调用规则如下:
- 如果用户定义有参构造函数,c++ 不提供默认无参构造函数,但是提供默认拷贝构造
- 如果用户定义拷贝构造函数,c++不会再提供其他构造函数
- 深拷贝: 在堆区重新申请空间进行拷贝操作
- 浅拷贝:简单的赋值拷贝操作
new 关键字开辟的是堆区 需要手动释放 析构函数不能进行释放
#include#include using namespace std; class person { public: person(int a,int eight ) { age = a; height = new int(eight); cout << "构造函数" << endl; } ~person() { // 浅拷贝带来的问题就是堆区内存的重复释放 需要利用深拷贝解决 if (height!=NULL) { delete height; height = NULL; } cout << "p析构函数" << endl; } person(const person& p) { age = p.age; //height = p.height;//这是编译器自己默认实现的,需要自己进行深拷贝操作 height = new int(*p.height);//堆上面申请的空间 cout << "拷贝构造函数" << endl; } public: int age; int* height;//指针类型 }; void test() { person p(10,90); cout << "p的年龄" << p.age << endl; person p2(p); cout << "p2的年龄" << p2.age << endl; } int main() { test(); return 0; }
4.6 初始化列表浅拷贝带来的问题就是堆区内存的重复释放 需要利用深拷贝解决
注意第八行冒号的位置
#include#include using namespace std; class person { public: person(int a, int b, int c) :age(a), height(b), money(c) {}; void show() { cout << age < 4.7类的对象作为类的成员 #include4.8 静态成员#include using namespace std; class phone { public: phone(string name) :name(name) { cout << "phone的构造方法" << endl; } ~phone() { cout << "phone的析构方法" << endl; } public: string name; }; class person { public: // phone p="大哥大" ----- phone p("大哥大) person(string prname, string phname):sname(prname),pname(phname) { cout << "person的构造方法" << endl; } ~person() { cout << "person的析构方法" << endl; } public: string sname; phone pname; }; void test() { person p("张三","大哥大"); cout << p.sname << "拿着" << p.pname.name << endl; } int main() { test(); return 0; }
- 静态成员变量
- 所有对象共享一份数据
- 在编译阶段分配内存
- 类内声明,类外初始化
- 静态成员函数
- 所有对象共享一个函数
- 静态成员函数只能访问静态成员变量
#include4.9c++ 对象模型和this指针#include using namespace std; class person { public: static int a;//静态变量内部定义 内外初始化 见第11行 static void getA() { cout << "a的结果为:" << a << endl;//静态函数不能使用非静态变量aaa } int aaa; }; int person::a = 0; void test() { person::getA(); } int main() { test(); return 0; }
- 空对象占用的内存为1字节
- 只有非静态成员变量属于类的对象上
class a{ }//空类大小为1字节 class a{ int a; }//此时类大小为4字节4.10 this 指针
- this指针指向被调用的成员函数所属对象
- 类的非静态成员函数中返回对象本身 *return this
#include4.11空指针调用成员函数#include using namespace std; class person { public: person(int name) { this->name = name; } void show() { cout << this->name << endl; } person& addPerson(person p2) { this->name += p2.name; return *this;//可以使用链式编程 返回函数自身 } int name; }; void test() { person p(33); person P2(33); p.addPerson(33).addPerson(33);//链式编程 p.show(); } int main() { test(); return 0; } #include4.12 const 修饰成员函数#include using namespace std; class person { public: person(int name) { this->name = name; } void show() { if (this == NULL)//增加程序的健壮性 { cout << "空指针访问" << endl; return; } cout << this->name << endl; } int name; }; int main() { person* p = NULL;//空指针 p->show(); return 0; } 常函数
成员函数后加const称之为常函数
常函数内部不可以修饰成员属性
成员属性添加mutable关键字后可以修改
常对象
声明对象之前添加const称之为常对象
常对象只能调用常函数
#include4.13友元 friend#include using namespace std; class person { public: person(int name, int money) { this->money = money; this->name = name; } void show() const { //常函数 //this->name = 100; this->money = 100; cout << this->name << endl; } void fun() {}; int name;//常函数不能修改 mutable int money;//常函数可以修改 }; void test() { } int main() { const person p(12, 13); p.show(); //p.fun();//常对象只能调用常函数 return 0; } 4.14 运算符重载四则运算
全局函数做友元
#include#include using namespace std; // 全局函数友元 class Building { friend void goodGayvisit(Building* p);//全局函数的友元 public: Building(); ~Building(); string sittingRoom; private: string bedRoom; }; Building::Building() { this->sittingRoom = "客厅"; this->bedRoom = "卧室"; } void goodGayvisit(Building* p) {//全局函数访问 cout << "好基友访问客厅" << p->sittingRoom << endl; cout << "好基友访问卧室" << p->bedRoom << endl; } Building::~Building() { cout << "Building 的析构函数" << endl; } void test() { Building p; goodGayvisit(&p);//函数参数需要指针,在此传递地址 } int main() { test(); return 0; } 类做友元
#include#include using namespace std; // 类友元 class BUiling { friend class gay;//友元类 public: BUiling(); ~BUiling(); string sitting; private: string bed; }; BUiling::BUiling() { this->bed = "卧室"; this->sitting = "客厅"; } BUiling::~BUiling() { } class gay { public: gay(); ~gay(); BUiling* bu; void visit(BUiling* bu); private: }; gay::gay() { bu = new BUiling; } void gay::visit(BUiling* p) { cout << p->sitting << endl; cout << p->bed << endl;//私有属性不可访问 需添加友元 } gay::~gay() { } void test() { gay gg; BUiling p; gg.visit(&p); } int main() { test(); return 0; } 成员函数做友元
与上述函数一致 加上友即可
可以进行函数重载
#include4.15 左移运算符重载#include using namespace std; // 运算符重载 class Person { friend Person operator-(Person& a, Person& b); public: Person(); ~Person(); public: int a; int b; }; Person::Person() { a = 3; b = 3; cout << "程序构造初始化" << endl; } Person operator-(Person& a, Person& b) { Person tem; tem.a = a.a + b.a; tem.b = a.b + b.b; return tem; } Person::~Person() { cout << "程序析构退出" << endl; } void test() { Person p1; p1.a = 1; p1.b = 2; Person p2; p2.a = 3; p2.b = 4; Person p3 = p1 - p2; cout << "a=" << p3.a << "b=" << p3.b << endl; } int main() { test(); return 0; } 就是重新定义输出 cout 使之可以直接对对象进行输出
4.16 递增运算符重载<< ++ – == !=
int a = 10; cout << a++ << endl;// a=10 cout<1前置递增(++a)返回的是引用
后置递增(a++)返回的是值
4.17 匿名函数仿函数 ()的重载
#include5.继承#include using namespace std; // 匿名对象 class MyAdd { public: int operator()(int a, int b) { return a + b; } MyAdd(); ~MyAdd(); }; int main() { MyAdd m; cout << m(1, 2) << endl; cout << MyAdd()(22, 22) << endl;// 匿名函数 return 0; }
- 继承的基本语法 class 子类 :继承方式 父类
#include#include using namespace std; // 继承 class base { public: base(); ~base(); void head() { cout << "head" << endl; } void body() { cout << "body" << endl; } void bottom() { cout << "bottom" << endl; } private: }; class son : public base {//son 继承 base类 public: void getson() { cout << "子类的方法" << endl; } }; int main() { son s; s.head(); s.body(); s.bottom(); s.getson(); return 0; } 5.1 继承中的对象模型
- 公有继承
- 保护继承
- 私有继承
5.2继承中的构造和析构顺序父类中所有非静态产成员属性都会被子类继承下去
5.2继承中同名成员处理现有父类构造 --子构造-子析构-父析构
5.3继承静态成员函数的处理方式同名成员–需要添加父类的作用域 Father:: a 否则直接调用就是调用的子类 子类会直接隐藏和父类同名成员函数
访问子类中的直接访问
访问父类的需要添加作用域
通过类方式访问 son::base::method 第一个::表示使用类的方式访问 第二个表示base的作用域
5.4多继承语法class 子类: 继承方式 父类1 ,继承方式 父类2
当父类出现成名成员 需要添加作用域
一般不建议使用
5.5 菱形继承使用虚继承解决数据不一致的问题 virtual 解决子类继承两份相同的数据,导致资源浪费毫无意义
6.多态 6.1多态的基本概念
- 多态满足条件
- 有继承关系
- 子类重写父类中的虚函数
- 多态使用条件
- 父类指针或者引用指向子类对象
#include6.2 纯虚函数#include using namespace std; // 继承 运行地址晚绑定 class Animal { public: virtual void speak() {// 不加 virtual 关键字 第24就是打印”动物在说话“ cout << "动物在说话" << endl; } }; class Cat :public Animal { public: void speak() { cout << "小猫在说话" << endl; } }; void dospeak(Animal& animal) {//父类指针或者引用指向子类对象 animal.speak(); } int main() { Cat cat; dospeak(cat); return 0; } 当类中有了纯虚函数, 这类成为抽象类
#include6.3虚析构和纯虚析构#include using namespace std; // 继承 class Animal { public: virtual void speak() = 0;// 纯虚函数 不能够实例化对象 子类必须进行函数重写 }; class Cat :public Animal { public: void speak() { cout << "小猫在说话" << endl; } }; int main() { Animal* c = new Cat;// 指针的方式可以使得new 其他子类 多态的一种体现 c->speak(); delete c;// 堆区使用之后必须进行释放 return 0; } 虚析构 可以解决父类指针释放子类对象不干净的问题 ---- 子类有数据开辟到堆区
(* a作为函数参数 可以使用 new A—a是A的实现类)
7文件操作 7.1写文件
#include7.2读文件#include #include using namespace std; // 文件的读写 int main() { ofstream ofs; ofs.open("exam.txt", ios::out); ofs << "测试" << endl; ofs.close();// 文件写之后需要进行文件关闭 return 0; } #include8、c++提高编程 8.1函数模板#include #include using namespace std; // 文件读 int main() { ifstream ifs; ifs.open("exam.txt", ios::in); if (!ifs.is_open()) { cout << "打开文件失败" << endl; return 0; } string buffer; while (getline(ifs, buffer)) { cout << buffer << endl; } ifs.close(); return 0; } #include8.2函数模板注意事项#include #include using namespace std; // 函数模板 template void mswap(T& a, T& b) { int tem; tem = a; a = b; b = tem; } int main() { int a = 1; int b = 2; // 自动推导确定数据类型 mswap(a, b); // 显示指定其数据类型 mswap (a, b); cout << a << endl; return 0; } 8.3普通函数和函数模板的区别
- 自动类型推导,必须推导出一致的数据类型T,才可以使用
- 模板必须要确定T的数据类型,才可以使用
8.4类模板和函数模板的区别
- 普通函数调用可以发生 *隐式类型转换=====add(10,‘c’)可以将‘c’转换为ASCII编码 99*
- 函数模板 用自动类型推导,不可以发生隐式类型转换
- 函数模板 用显式指定类型,可以发生隐式类型转换
- 函数模板也可以发生重载
- 类模板没有自动类型推到的使用方式
- 类模板在模板参数列表中可以有默认参数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RvUuvypT-1637113785266)(C:Users15281AppDataRoamingTyporatypora-user-imagesimage-20211103165414699.png)]
8.5 类模板中成员函数的创建时机9.STL使用
- 普通类中的成员函数一开始就可以创建
- 类模板的成员函数在调用时才创建
分为 容器、算法和迭代器



