基础C++知识

1. 基本模板

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. // 输出
  6. cout << "hello naka " << endl;
  7. system("pause");
  8. return 0;
  9. }

2. 注释

///* */

3. 变量 常量

  1. 变量 为一个一定大小的空间取一个名字,方便之后使用
  2. 常量,定义初始化之后不允许修改
    1. #defineconst

4. 关键字

  1. 修饰符类型:

image.png

  1. 用户标识符区分大小写、见名知意

5. 数据类型

6. 运算符

7. 程序流程结构

  1. 顺序、选择、循环
  2. if 、switch 、? : 、 for 、while 、do while

8. 数组

  1. 数组名,数组名指示该数组在内存中的首地址,普通变量取址符&
  2. 二维数组定义时,最少给出 int a[][2] = {{1},{1,2}}

9. 函数

  1. 函数的定义、调用、值传递、声明(被调用的函数写在前面)
  2. 函数的分文件编写
    1. 创建.h后缀的头文件
    2. 创建.cpp后缀的源文件
    3. 在头文件中写函数的声明
    4. 在源文件中写函数的定义
    5. 在使用函数的文件中引入该头文件 #include "我的头文件.h"
  3. 函数的默认参数 void func(int a, int b= 10){}
    1. 有默认值的参数必须放在参数列表的后面


  4. 函数重载

  5. 在同一个作用域下;函数名称相同;函数参数类型不同 或者个数不同或 顺序不同

  6. 函数的返回值不能作为函数重载的条件

    10. 指针

  7. 定义,使用

    1. int a, *p;
    2. p = &a;
    3. *p = 1000;
    4. // 空指针,用来初始化指针,不能进行访问
    5. p = NULL;
  8. 常量指针,用const修饰指针const int * p,指针的指向可以修改,指针所指向的值不可修改

    1. const int * p
  9. 指针常量,int * const p,指针的指向不可以改,指针指向的值可以改
    1. int * const p
  10. 指针和函数(参数)
    1. 值传递
    2. 地址传递

11. 结构体

  1. 定义,使用 ```cpp struct Student { string name; int age; int score; };

struct Student s; // 这里的struct可以省略 s.name = “Naka”;

struct Student s1 = {“Naka”, 41, 98};

  1. 2. 结构体数组
  2. 2. 结构体指针,使用`->`访问成员
  3. 2. 结构体或结构体指针做函数参数
  4. 2. 使用const修饰结构体变量的定义,防止误修改
  5. <a name="qS4W5"></a>
  6. ## new操作符
  7. 1. new的基本语法
  8. 1. new创建的变量会被存放在堆区,由程序员管理创建与释放
  9. 1. new返回的是该数据类型的指针
  10. 1. 使用`delete`关键字释放
  11. ```cpp
  12. int *p = new int(10);
  13. delete p;
  1. 使用new创建数组 int *p = new int[10];
    1. 释放数组 delete [] p;

引用

  1. 数据类型 &变量2 = 变量1;
  2. 两个变量操作的是同一个空间
  3. 引用必须要初始化,指明对谁的引用
    1. 引用一旦初始化后,就不可更改引用的指向
  4. 在函数传参时,可以用引用作为形参,这样也可以通过形参来修改实参
  5. 引用可以作为函数的返回值

    1. int& test(){
    2. static int a = 10;
    3. return a; // 返回了a的引用
    4. }
    5. ...
    6. int &b = test();
    7. cout << b << endl; // 10
    8. test() = 1000; // 函数的调用作为等式的左值
    9. cout << b << endl; // 1000
  6. 引用的原理也是指针常量

类和对象

  1. 面向对象三大特征:封装、继承、多态。万物皆对象
  2. 定义方式 class 类名 { 访问权限: 属性 / 方法 } ```cpp

    define PI 3.14

class Circle { private: double c_r = 10; string c_name;

public: void setName(string name) { c_name = name; } string getName() { return c_name; } void setR(double r) { c_r = r; } double zhouchang() { return 2 PI c_r; } };

int main() { // 实例化 Circle c; c.setName(“圆”); c.setR(11.2); cout << “周长:” << c.zhouchang() << endl;

  1. system("pause");
  2. return 0;

}

  1. 3. 访问权限:
  2. 1. 公共`public`
  3. 1. 保护`protected`,类外不可访问,继承类可以访问
  4. 1. 私有`private`,类外不可访问,继承类不可以访问
  5. 1. 默认访问权限为私有
  6. <a name="yU6r2"></a>
  7. ## 构造函数和析构函数
  8. 1. 编译器自动提供(空实现的),也可以自己写
  9. <a name="O6MKt"></a>
  10. ### 构造函数
  11. 1. 在创建对象时为对象的成员属性赋值
  12. 1. `类名(){ }` 没有返回值也不写void,名字与类名相同
  13. 1. 可以有参数,发生重载
  14. 2. 两种分类方法:
  15. 1. 按参数分 有参、无参
  16. 1. 按类型分 普通、拷贝
  17. 3. 三种调用方法:
  18. 1. 括号法
  19. 1. `Person p1;` 调用默认无参构造函数 注意不加`()`
  20. 1. `Person p2(10);` 调用有参普通构造函数 将属性值传入
  21. 1. `Person p3(p2);` 调用有参拷贝构造函数
  22. 2. 显示法
  23. 1. `Person p1;` 调用默认无参构造函数 注意不加`()`
  24. 1. `Person p2 = Person(10);` 调用有参普通构造函数 将属性值传入
  25. 1. `Person p3 = Person(p2);` 调用有参拷贝构造函数
  26. 3. 隐式转换法
  27. 1. `Person p1 = 10;` 相当于`Person p1 = Person(10);`
  28. 1. `Person p2 = p1;` 相当于`Person p2 = Person(p1);`
  29. 4. 拷贝构造函数的写法
  30. ```cpp
  31. class Person{
  32. string name;
  33. Person(const Person &p){
  34. name = p.name; // 调用此构造函数的对象会被赋予同p相同的属性值
  35. }
  36. }
  1. 拷贝构造函数的调用时机
    1. 用一个已有的对象来创建一个新对象
    2. 值传递的方式给函数参数传值
    3. 值方式返回局部对象

析构函数

  1. 对象销毁前系统自动调用,执行一些清理工作
    1. ~类名(){ } 没有返回值也不写void,名字与类名相同,在名称前加~
    2. 不可以有参数

深拷贝与浅拷贝

  1. 浅拷贝:简单的复制拷贝操作,int a, b; a = 10; b = a;
  2. 深拷贝:在堆区重新申请空间,进行拷贝操作,int a = 10; int *b = new int(a);

构造函数初始化列表

  1. 初始化各个属性值
  2. 类名(参数1, 参数2): 属性1(参数1), 属性2(参数2) { }

类对象作为类的成员

静态成员

静态成员变量

  1. 所有对象共享同一份数据
  2. 在编译阶段分配内存
  3. 类内声明,类外初始化

    静态成员函数

  4. 定义,在函数的返回类型前加staticstatic coid func(){ }

  5. 访问方式
    1. 对象名.方法名();
    2. 类名::方法名();
  6. 静态方法只能访问静态属性,不能访问其他属性
  7. 静态成员函数也具有访问权限
  8. 所有对象共享同一个静态成员函数

  9. 空对象占一个字节(没有一个成员的类对象)

  10. 静态成员不属于某一个对象,所以静态成员单独存放,不占对象的内存空间
  11. 成员函数和成员属性也单独存放,只有非静态成员变量属于类的对象上 才占对象的内存空间

this指针

  1. this指针指向被调用的成员函数所属的对象,用来区分调用该成员函数的对象时哪一个
  2. this指针隐含在每一个非静态成员函数内,直接使用
  3. 当形参和成员名相同时,可用this指针来区分
  4. 在类的非静态成员函数中返回对象本身时,可使用return *this; ```cpp class Person{ public: int age; Person(int age) {
    1. this->age = age;
    } // 返回引用 !! Person& add10(){
    1. this->age += 10;
    2. return *this;
    } }

// 调用 Person p(10); p.add10().add10();

  1. 1. 空指针(`Person *p = NULL;`)可以访问成员函数,需要注意若函数内使用了成员变量(隐含有this指针) 则会出错,否则可以正常访问。
  2. <a name="Xnzqu"></a>
  3. ### const修饰成员函数
  4. **常函数**
  5. - 成员函数后加const后称为常函数
  6. - 常函数内不可以修改成员属性
  7. - 成员属性声明时加关键字mutable后,在常函数中依然可以修改
  8. ```cpp
  9. class Person{
  10. public:
  11. int age;
  12. Person(int age) {
  13. this->age = age;
  14. }
  15. void func() const {
  16. age = 10; // 出错
  17. }
  18. }
  1. this指针的本质是一个指针常量 Person * const this; 其指向不可以修改
  2. 在成员函数后加上const后,就把this指针变成了常量指针 const Person * const this; 其指向的值也不可以修改

常对象

  • 声明对象前加const称为常对象 const Person p;
  • 常对象只能调用常函数,因为普通成员函数可以修改成员属性
  • 其属性不允许被修改,否则在成员属性的定义前加mutable

友元

定义:允许部分东西访问类的私有属性
关键字friend

全局函数做友元

  • 让一个全局函数可以访问一个类的私有成员 ```cpp class Person { friend void personFriend(Person* p); // 声明该全局函数为友元 private: int age; public: Person(int age) {
    1. this->age = age;
    } };

// 全局函数做友元 void personFriend(Person* p) { cout << “全局函数做友元 访问私有属性值:” << p->age << endl; }

void test() { Person p(40); personFriend(&p); }

  1. <a name="uQDzl"></a>
  2. ### 类做友元
  3. - 让一个类可以访问另一个类的私有成员
  4. ```cpp
  5. class Person {
  6. friend class Chinese; // 声明为友元
  7. private:
  8. int age;
  9. public:
  10. Person(int age) {
  11. this->age = age;
  12. }
  13. };
  14. // 类做友元
  15. class Chinese {
  16. public:
  17. Person* p;
  18. Chinese() {
  19. p = new Person(30);
  20. }
  21. void visit() {
  22. cout << "类做友元 访问私有属性 " << p->age << endl;
  23. }
  24. };
  25. void test() {
  26. Chinese c;
  27. c.visit();
  28. }

成员函数做友元

  • 让一个类的部分成员函数可以访问另一个类的私有成员
  • 前向声明,告诉编译器有这么一个类,但编译器不知道其大小 也不能访问。声明、预定使用、定义、使用 ```cpp class Person; // 前向声明该类,但具体使用还是只能在类定义之后

// 成员函数做友元 class Japanese { private: Person* p; // 预定使用 public: int m_age; Japanese(int age); // 在类外实现 void visit(); }; class Person { friend void Japanese::visit(); // 声明为友元 private: int age; public: Person(int age) { this->age = age; } }; // 在类外实现成员函数,因为要在前向声明的类定义之后 Japanese::Japanese(int age) { m_age = age; p = new Person(age); } void Japanese::visit() { cout << “成员函数做友元 访问私有属性 “ << p->age << endl; } void test() { Japanese j(20); j.visit(); }

  1. <a name="NruPE"></a>
  2. ## 运算符重载
  3. **概念**:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型<br />要用了再学
  4. <a name="m6lgo"></a>
  5. ## 继承
  6. **优点**:代码复用<br />**语法** 定义子类时,`class 子类: 继承方式 父类{ };`
  7. - 子类 - 派生类
  8. - 父类 - 基类
  9. - 构造与析构的顺序,创建子类对象时
  10. - 父类构造 -> 子类构造 -> 子类析构 -> 父类析构
  11. - 当子类和父类的成员属性`m_A`同名时,使用子类对象`Son s;`直接访问`s.m_A;`的是子类成员属性,外加父类作用域`s.Base::m_A`才能访问父类成员属性,访问父类的同名成员函数`s.Base::func();`
  12. <a name="vIswq"></a>
  13. ### 继承方式
  14. 1. 公共继承 `public`
  15. 1. 保护继承 `protected`
  16. 1. 私有继承 `private`
  17. | 父类 | 子类1(公共继承) | 子类2(保护继承) | 子类3(私有继承) |
  18. | --- | --- | --- | --- |
  19. | 公共权限成员 | 公共权限 | 保护权限 | 私有权限 |
  20. | 保护权限成员 | 保护权限 | | |
  21. | 私有权限成员 | 不可访问 | | |
  22. 4. 父类的私有成员在子类中即使不能被访问,但还是被继承了。
  23. <a name="LGAhj"></a>
  24. ### 多继承
  25. **语法**:`class 子类: 继承方式 父类1, 继承方式 父类2{ };`
  26. 1. 当多个父类中存在同名的成员时,子类访问时需要加作用域区分
  27. 1. 菱形继承时,可能存在数据浪费(两个父类存在同名的数据,子类无法确定是使用父类1的数据还是父类2的数据)
  28. 1. 解决,使用**虚继承**,在继承之前加关键字`virtual`
  29. ```cpp
  30. class Animal{
  31. public:
  32. int m_age;
  33. }
  34. class Sheep: virtual public Animal{ };
  35. class Tuo: virtual public Animal{ };
  36. class SheepTuo: public Sheep, public Tuo{ };
  37. SheepTuo st;
  38. st.Sheep::m_age = 100;
  39. st.Tuo::m_age = 200;
  40. cout << st.m_age << endl; // 200

多态

两类:

  • 静态多态,函数重载、运算符重载 函数地址早绑定 - 编译阶段确定函数地址
  • 动态多态,派生类、虚函数实现运行时多态 函数地址晚绑定 - 运行阶段确定函数地址
  1. class HomePage {
  2. public:
  3. // 虚函数
  4. virtual void contain() {
  5. cout << "主页面中间" << endl;
  6. }
  7. };
  8. class MyPage: public HomePage {
  9. public:
  10. // 重写父类的虚函数
  11. void contain() {
  12. cout << "我的页面中间" << endl;
  13. }
  14. };
  15. void doDraw(HomePage &hp) { // 子类可以自动转化为父类
  16. hp.contain();
  17. }
  18. void test(){
  19. MyPage mp;
  20. doDraw(mp); // 没加virtual 主页面,加了virtual 我的页面,根据传入的对象调用
  21. }

动态多态实现条件

  • 有继承关系
  • 子类重写父类中的虚函数

多态使用:父类指针或引用指向子类对象