C++基础速通

1.C++与C语言的关系

C++保留了C语言的大部分语法,并增加了类、对象、集成、多态、函数重载等能力。已经学过C,因此本课程不重新讲变量、循环、数组和指针,而是重点学习C++对程序结构的组织方式。

2.C++特点

  1. 在支持C语言的基础上,全面支持面向对象编程。
  2. 编程领域广泛,功能强大(最难的编程语言之一)。
  3. C++语言的标准一直保持着更新,本次课程主要以ISO C++98标准为主。
  4. 为数不多的支持底层操作的面向对象编程语言。
  5. 在面向对象的语言中执行效率极高。

3.面向对象编程的重要知识点

  • 对象
  • 封装
  • 继承
  • 多态

封装、继承、多态也被称为面向对象编程的三大特性。

4.面向过程与面向对象的区别(重点)

【例子】:把大象装进冰箱需要几步?

  1. 打开冰箱
  2. 把大象放进去
  3. 关闭冰箱

程序会编写成一组函数,数据在函数之间传递。

面向对象中关注"对象"。

  • 大象具有移动等行为
  • 冰箱具有打开、关闭、保存物品的功能。
  • 程序通过对象之间的调度完成任务。

面向过程

主要关注"怎么做"

把程序拆成一步一步的流程、函数,以步骤为核心,数据和函数分离。

代表语言C语言

面向对象

关注"谁来做"

把程序拆解为对象(实体),将数据(属性)+操作数据的方法封在一起。

代表语言:Java、C++、python

面向过程:按照流程解决问题

面向对象:把事物拆分类别,依靠类别的实体协作解决问题。

5.环境搭建

单纯论C++的开发环境,没有严格的要求,为了学习的方便,直接使用后面课程的开发环境。即QtCreator。

安装完成后为了使其支持中文输出,更改下面的编码:

设置完成后,重新启动Qt Creator,就可以新建一个C++的项目了。

1.点击

2.在弹出的窗口中,按照下图所示进行操作

3.在弹出的窗口中,输入项目名称,在设定项目路径,最后点击下一步。需要注意的是不得出现任何中文的字符和特殊字符。

4.在弹出的窗口中,直接点击下一步即可。

5.在项目管理界面,直接点击完成

6.可以看到新项目中包含了两个文件

.pro文件为项目配置文件,通常无需手动编辑

.cpp文件为C++的源代码文件,用于编写C++代码。

cpp 复制代码
// 包含头文件,标准输入输出流
// 在C++源码中,头文件不需要包含.h
#include <iostream>

// 使用标准名字空间,不要删
using namespace std;

// 主函数,程序的入口
int main()
{
    // 连续输出一个字符串和换行符
    cout << "Hello World!" << endl;
    // 返回一个0
    return 0;
}
```

点击左下角的小三角(快捷键:ctrl+R),即可运行项目

补充几个快捷键的使用技巧:

1、ctrl+c 复制

2、ctrl+v 粘贴

3、ctrl+R 编译+运行

4、Alt+0 显式和隐藏边栏

5、ctrl+A 全选 ,再点击ctrl+i 对齐。 本页全部代码排版

6、ctrl+F搜索+替换

7、ctrl+z 回滚

8、ctrl+s 保存

6.键盘输入

可以使用cin把用户再命令行中输入的内容赋值到变量中。

cpp 复制代码
```cpp
#include <iostream>


using namespace std;


int main()
{
    int a;

    // C++的字符串类型
    string str;

    cout << "请输入一个数字和字符串" << endl;
    cin >> a >> str;    // 接收键盘的输入,一个整数和一个字符串,可以连续操作
    cout << a << " " << str << endl;

    return 0;
}
```

如果cin输入的字符串需要包含空格,则可以使用下面的方式:

cpp 复制代码
```cpp
#include <iostream>


using namespace std;


int main()
{
    int a;

    // C++的字符串类型
    string str;

    cout << "请输入一个数字和字符串" << endl;
    cin >> a >> str;    // 接收键盘的输入,一个整数和一个字符串,可以连续操作
    cout << a << " " << str << endl;

    return 0;
}
```

7.引用(掌握)

7.1概念

指针相当于对于某一目标变量起一个别名。

操作引用与操作变量完全相同。

cpp 复制代码
```cpp
#include <iostream>

using namespace std;


int main()
{
    int a = 1;
    // 表示b是a的引用
    int &b = a;

    cout << a << " " << &a << endl; // 1 0x61fe88
    cout << b << " " << &b << endl; // 1 0x61fe88
    return 0;
}
```

7.2引用的特点

可以改变引用的值,但是不能再次成为其他变量的引用。

cpp 复制代码
```cpp
#include <iostream>

using namespace std;


int main()
{
    int a = 1;
    // 表示b是a的引用
    int &b = a;

    cout << a << " " << &a << endl; // 1 0x61fe88
    cout << b << " " << &b << endl; // 1 0x61fe88
    return 0;
}
```

声明引用时,必须要做初始化。

cpp 复制代码
```cpp
#include <iostream>

using namespace std;


int main()
{
    int a = 1;
    // 表示b是a的引用
    int &b = a;

    cout << a << " " << &a << endl; // 1 0x61fe88
    cout << b << " " << &b << endl; // 1 0x61fe88
    return 0;
}
```

声明引用的时候,不能直接初始化为NULL,如果想要给NULL取别名,需要使用const关键字修饰。

cpp 复制代码
```cpp
#include <iostream>

using namespace std;


int main()
{
    int a = 1;

//    int &b = NULL; // 错误不能直接给NULL取别名
    const int &b = NULL; // 如果要给NULL取别名,需要const

    cout << a << " " << &a << endl; // 3 0x61fe88
    cout << b << " " << &b << endl; // 3 0x61fe88
    return 0;
}
```

声明引用的时候,初始化的值可以是纯数值,但是需要使用const进行修饰,表示改引用为常量引用,这样引用的值不可变。

cpp 复制代码
```cpp
#include <iostream>

using namespace std;


int main()
{
    const int &b = 12;
//    b++; // 错误常量引用的数值无法被改变
    cout << b << " " << &b << endl;
    return 0;
}
```

7.3 引用作为函数参数

cpp 复制代码
```cpp
#include <iostream>

using namespace std;


int main()
{
    const int &b = 12;
//    b++; // 错误常量引用的数值无法被改变
    cout << b << " " << &b << endl;
    return 0;
}
```

7.4 const引用参数

如果函数只想读取参数,不修改参数,可以使用const引用。

cpp 复制代码
```cpp
#include <iostream>

using namespace std;


int main()
{
    const int &b = 12;
//    b++; // 错误常量引用的数值无法被改变
    cout << b << " " << &b << endl;
    return 0;
}
```

8.string字符串类(掌握)

string不是C++的基本数据类型,它是一个C++标准库中的字符串类,使用时需要引入头文件#include<string>不包含.h。

string在绝大多数的情况下可以代替C语言的字符数组,不必担心内存是否足够和字符串处理函数,可以完成各种情况下的字符串处理功能。

cpp 复制代码
```cpp
#include <iostream>

using namespace std;


int main()
{
    const int &b = 12;
//    b++; // 错误常量引用的数值无法被改变
    cout << b << " " << &b << endl;
    return 0;
}
```

两种方式都可以,但是在C++中更推荐使用at函数,原因是at函数更安全。但是\[\]的方式效率更高。

cpp 复制代码
```cpp
#include <iostream>

using namespace std;

int main()
{
    string str = "helloworld";
    cout << str.size() << endl; // 10
    cout << str.length() << endl; // 10

//    cout << str[1] << endl; // e
    cout << str.at(100) << endl; // e
    cout << "helloworld" << endl;
    return 0;
}
```

string可以使用for循环将数据取出。

cpp 复制代码
```cpp
#include <iostream>

using namespace std;

int main()
{
    string str = "helloworld";
    cout << str.size() << endl; // 10
    cout << str.length() << endl; // 10

//    cout << str[1] << endl; // e
    cout << str.at(100) << endl; // e
    cout << "helloworld" << endl;
    return 0;
}
```

9.函数重载(掌握)

C++中允许多个函数使用同一个名称,这种用法就是函数重载。函数重载要求函数名称相同,但是参数不同(类型、数量、前后顺序)。与返回值等其他类型无关。

cpp 复制代码
#include <iostream>

using namespace std;

void print_show(int i)
{
    cout << "调用了int1重载:" << i << endl;
}

void print_show(int i,int i2)
{
    cout << "调用了int2重载:" << i << i2 << endl;
}


void print_show(double d)
{
    cout << "调用了double重载:" << d << endl;
}

void print_show(string s)
{
    cout << "调用了string重载:" << s << endl;
}


// 错误,返回值类型,不能作为重载条件
//double print_show(int i)
//{
//    cout << "调用了int1重载:" << i << endl;
//}

int main()
{
    print_show(1);
    return 0;
}

10.类与对象(重点)

10.1 概念

类:类是一个抽象的概念,用于描述一类对象的特点。

对象:根据类的概念所创造的实体。

【思考】:一个对象可以没有对应的类吗?

不可以。

10.2 类的内容

类中最基础的内容包括两个部分,一个是属性,一个是行为。

属性:表示一些特征项的数值,例如:身高、体重、年龄、颜色、型号等等,这些特征的数值一般使用变量进行存储,而类中的变量也被称为"成员变量"。

行为:表示能执行的动作,能做什么事情。例如:吃饭睡觉打游戏等,行为一般通过函数来实现,而类中的函数也被称为"成员函数"。

【例子】以手机为例,来说明类的定义。

规定手机能播放音乐、运行游戏、打电话。手机有品牌、型号、重量属性。

cpp 复制代码
#include <iostream>

using namespace std;

// 帕斯卡命名法(大驼峰命名法)
// 每个单词首字母是大写
class MobilePhone
{
public:     // 权限:public公有权限(最开放的权限)
    // 成员变量(属性)
    string brand;   // 品牌
    string model;   // 型号
    int weight;     // 重量

    // 成员函数(行为)
    void play_music()
    {
        cout << "只因你太美,哒哒哒" << endl;
    }

    void run_game()
    {
        cout << "王者荣耀、元神启动、三角洲行动" << endl;
    }

    void call()
    {
        cout << "歪歪歪 你好呀" << endl;
    }

};

int main()
{

    return 0;
}

10.3 对象的创建

在C++中存在两类对象。

栈内存对象

对象所在的{}执行完毕后,自动被销毁

cpp 复制代码
```cpp
#include <iostream>

using namespace std;

// 帕斯卡命名法(大驼峰命名法)
// 每个单词首字母是大写
class MobilePhone
{
public:     // 权限:public公有权限(最开放的权限)
    // 成员变量(属性)
    string brand;   // 品牌
    string model;   // 型号
    int weight;     // 重量

    // 成员函数(行为)
    void play_music()
    {
        cout << "只因你太美,哒哒哒" << endl;
    }

    void run_game()
    {
        cout << "王者荣耀、元神启动、三角洲行动" << endl;
    }

    void call()
    {
        cout << "歪歪歪 你好呀" << endl;
    }

};


int main()
{
    MobilePhone mp; // 栈内存对象mp
    mp.brand = "小米";
    mp.model = "15";
    mp.weight = 300;

    cout << mp.brand << " " << mp.model << " " << mp.weight << endl;

    mp.play_music();
    mp.run_game();
    mp.call();

    return 0;
}
```

堆内存对象

必须使用new关键字创建,使用指针存储,使用delete销毁空间。如果不使用delete销毁,则堆内存对象将会持续存在,从而导致内存泄漏。

cpp 复制代码
```cpp
#include <iostream>

using namespace std;

// 帕斯卡命名法(大驼峰命名法)
// 每个单词首字母是大写
class MobilePhone
{
public:     // 权限:public公有权限(最开放的权限)
    // 成员变量(属性)
    string brand;   // 品牌
    string model;   // 型号
    int weight;     // 重量

    // 成员函数(行为)
    void play_music()
    {
        cout << "只因你太美,哒哒哒" << endl;
    }

    void run_game()
    {
        cout << "王者荣耀、元神启动、三角洲行动" << endl;
    }

    void call()
    {
        cout << "歪歪歪 你好呀" << endl;
    }

};


int main()
{
    MobilePhone mp; // 栈内存对象mp
    mp.brand = "小米";
    mp.model = "15";
    mp.weight = 300;

    cout << mp.brand << " " << mp.model << " " << mp.weight << endl;

    mp.play_music();
    mp.run_game();
    mp.call();

    return 0;
}
```

11.封装(重点)

在上一节中MObilePhone类与结构体差别不大,实际上可以认为结构体就是一种完全开放的类。

封装指的是,将类的一些属性和行为隐藏,重新提供外部的访问接口。封装可以提升代码的安全性,并且可以让程序员更关注上层架构而非内部细节。

cpp 复制代码
```cpp
#include <iostream>

using namespace std;

// 帕斯卡命名法(大驼峰命名法)
// 每个单词首字母是大写
class MobilePhone
{
public:     // 权限:public公有权限(最开放的权限)
    // 成员变量(属性)
    string brand;   // 品牌
    string model;   // 型号
    int weight;     // 重量

    // 成员函数(行为)
    void play_music()
    {
        cout << "只因你太美,哒哒哒" << endl;
    }

    void run_game()
    {
        cout << "王者荣耀、元神启动、三角洲行动" << endl;
    }

    void call()
    {
        cout << "歪歪歪 你好呀" << endl;
    }

};


int main()
{
    MobilePhone mp; // 栈内存对象mp
    mp.brand = "小米";
    mp.model = "15";
    mp.weight = 300;

    cout << mp.brand << " " << mp.model << " " << mp.weight << endl;

    mp.play_music();
    mp.run_game();
    mp.call();

    return 0;
}
```

12.构造函数(重点)

12.1 基本使用

构造函数是一种特殊的成员函数,用于创建对象时初始化。创建对象时必须直接或间接调用当前类的任意一个构造函数,写法上有以下的要求:

  1. 函数名称必须与类完全相同
  2. 创建对象时自动调用
  3. 构造函数没有返回值类型
  4. 可以进行重载
  5. 如果程序员不编写构造函数,编译器会自动添加一个无参数的构造函数

手动添加构造函数后,编译器将不会再自动添加默认无构造函数了。

构造函数再创建对象时,常用于给对象的属性赋予初始值

cpp 复制代码
#include <iostream>

using namespace std;


class MobilePhone
{
private:    // 权限:私有权限,也是最封闭权限,只能在类内访问
    // 成员变量(属性)
    string brand;   // 品牌
    string model;   // 型号
    int weight;     // 重量

public:     // 权限:public公有权限(最开放的权限)

    MobilePhone()
    {
        brand = "小米";
        model = "60 pro";
        weight = 200;
    }

    string get_brand()
    {
        return brand;
    }

    string get_model()
    {
        return model;
    }

    int get_weight()
    {
        return weight;
    }
};


int main()
{
    cout << "程序开始执行" << endl;
    MobilePhone* mp  = new MobilePhone; // 堆内存对象

    cout << mp->get_brand() << endl;
    cout << mp->get_model() << endl;
    cout << mp->get_weight() << endl;

    delete mp;  // 手动销毁

    return 0;
}

构造函数也支持函数重载

cpp 复制代码
#include <iostream>

using namespace std;


class MobilePhone
{
private:    // 权限:私有权限,也是最封闭权限,只能在类内访问
    // 成员变量(属性)
    string brand;   // 品牌
    string model;   // 型号
    int weight;     // 重量

public:     // 权限:public公有权限(最开放的权限)

    MobilePhone()
    {
        brand = "小米";
        model = "60 pro";
        weight = 200;
    }

    // 有参构造函数
    MobilePhone(string b, string m,int w)
    {
        brand = b;
        model = m;
        weight = w;
    }

    string get_brand()
    {
        return brand;
    }

    string get_model()
    {
        return model;
    }

    int get_weight()
    {
        return weight;
    }
};


int main()
{
    cout << "程序开始执行" << endl;
    MobilePhone* mp  = new MobilePhone("8848","钛金手机",500); // 堆内存对象

    cout << mp->get_brand() << endl;
    cout << mp->get_model() << endl;
    cout << mp->get_weight() << endl;

    delete mp;  // 手动销毁

    MobilePhone mp2;        // 调用无参构造函数
    MobilePhone mp3("vivo","70",300); // 调用有参构造函数

    return 0;
}

12.2 构造初始化列表

构造初始化列表是一种更简单的给成员变量赋予初始值的写法。

cpp 复制代码
#include <iostream>

using namespace std;


class MobilePhone
{
private:    // 权限:私有权限,也是最封闭权限,只能在类内访问
    // 成员变量(属性)
    string brand;   // 品牌
    string model;   // 型号
    int weight;     // 重量

public:     // 权限:public公有权限(最开放的权限)


    MobilePhone()
        :brand("小米"),model("60 pro"),weight(200)
    {
        cout << "构造函数被执行了" << endl;
//        brand = "华为";
    }

    // 有参构造函数
    MobilePhone(string b, string m,int w)
    {
        brand = b;
        model = m;
        weight = w;
    }

    string get_brand()
    {
        return brand;
    }

    string get_model()
    {
        return model;
    }

    int get_weight()
    {
        return weight;
    }
};


int main()
{
    MobilePhone mp2;        // 调用无参构造函数
    cout << mp2.get_brand() << endl;
    cout << mp2.get_model() << endl;
    cout << mp2.get_weight() << endl;

//    MobilePhone mp3("vivo","70",300); // 调用有参构造函数

    return 0;
}

当构造函数局部变量与局部变量重名时,除了使用后面学习的this指针之外,也可以使用构造初始化列表来区分。

12.3 拷贝构造函数

12.3.1 概念

当程序员不手动编写构造函数时,编译器会自动添加一个拷贝构造函数,使对象的创建可以通过这个构造函数实现。

cpp 复制代码
#include <iostream>

using namespace std;


class MobilePhone
{
private:    // 权限:私有权限,也是最封闭权限,只能在类内访问
    // 成员变量(属性)
    string brand;   // 品牌
    string model;   // 型号
    int weight;     // 重量

public:     // 权限:public公有权限(最开放的权限)


    MobilePhone()
        :brand("小米"),model("60 pro"),weight(200)
    {
        cout << "构造函数被执行了" << endl;
//        brand = "华为";
    }

    // 有参构造函数
    MobilePhone(string brand, string model,int weight)
        :brand(brand),model(model),weight(weight)
    {
    }

    // 手动编写编译器默认添加的拷贝构造函数
    MobilePhone(const MobilePhone &mp)
    {
        brand = mp.brand;
        model = mp.model;
        weight = mp.weight;
    }

    string get_brand()
    {
        return brand;
    }

    string get_model()
    {
        return model;
    }

    int get_weight()
    {
        return weight;
    }
};


int main()
{
    MobilePhone mp1("小米","13",300); // 调用有参构造函数,栈内存对象

    MobilePhone mp2(mp1);   // 调用拷贝构造函数
    cout << mp2.get_brand() << endl;
    cout << mp2.get_model() << endl;
    cout << mp2.get_weight() << endl;

    return 0;
}

12.3.2 浅拷贝

cpp 复制代码
#include <iostream>
#include <string.h>

using namespace std;

class Dog
{
private:
    char *name;
public:
    Dog(char *n)
    {
        name = n;
    }

    void show_name()
    {
        cout << name << endl;
    }
};


int main()
{
    char arr[20] = "旺财";
    Dog d1(arr);    // 调用有参构造函数
    Dog d2(d1);     // 调用拷贝构造函数

    strcpy(arr,"大黄");

    d1.show_name(); // 大黄
    d2.show_name(); // 大黄


    return 0;
}
‌

这种情况必须手动编写拷贝构造函数,使每次赋值都创建一个新的副本,从而让每个对象单独持有自己的成员变量。这种方式也被称为"深拷贝"。

12.3.3 深拷贝

cpp 复制代码
#include <iostream>
#include <string.h>

using namespace std;

class Dog
{
private:
    char *name;
public:
    Dog(char *n)
    {
        name = new char[20];
        strcpy(name,n);
    }

    // 拷贝构造函数
    Dog(const Dog &d)
    {
        name = new char[20];
        strcpy(name,d.name);
    }

    void show_name()
    {
        cout << name << endl;
    }
};


int main()
{
    char arr[20] = "旺财";
    Dog d1(arr);    // 调用有参构造函数
    Dog d2(d1);     // 调用拷贝构造函数

    strcpy(arr,"大黄");

    d1.show_name(); // 旺财
    d2.show_name(); // 旺财


    return 0;
}

13.析构函数(重点)

析构函数是与构造函数对立的函数

|------------|-----------------|
| 构造函数 | 析构函数 |
| 创建对象时手动调用 | 当对象销毁时,自动调用 |
| 函数名称是类名 | 函数名称是~类名 |
| 构造函数可以重载 | 析构函数没有参数,不能进行重载 |
| 用于创建对象时初始化 | 用于销毁对象时释放资源 |
| 没有返回值 | 没有返回值 |

cpp 复制代码
```cpp
#include <iostream>
#include <string.h>

using namespace std;

class Dog
{
private:
    char *name;
public:
    Dog(char *n)
    {
        name = new char[20];
        strcpy(name,n);
    }

    // 拷贝构造函数
    Dog(const Dog &d)
    {
        name = new char[20];
        strcpy(name,d.name);
    }

    void show_name()
    {
        cout << name << endl;
    }

    ~Dog()
    {
        cout << "析构函数被调用了" << endl;
        delete []name;  // []表示销毁的是连续的空间
    }
};


int main()
{
    char arr[20] = "旺财";
    Dog d1(arr);    // 调用有参构造函数
    Dog d2(d1);     // 调用拷贝构造函数

    strcpy(arr,"大黄");

    d1.show_name(); // 旺财
    d2.show_name(); // 旺财


    return 0;
}
```
相关推荐
C++ 老炮儿的技术栈1 小时前
MFC CPtrArray的用法
开发语言·数据结构·c++·算法·mfc·c
是立不是利1 小时前
深入理解JavaScript事件委托
开发语言·前端·javascript
啊阿狸不会拉杆1 小时前
《计算机网络-自顶向下方法》6.4 交换局域网 读书笔记
开发语言·计算机网络·php
心中有你02141 小时前
Python Tkinter 情侣恋爱日记桌面小程序(本地文件存储,无数据库)
开发语言·python
疯狂打码的少年2 小时前
【计算机网络】OSI/RM七层模型(层次结构、各层功能速览)
开发语言·笔记·计算机网络·php
小灰灰搞电子2 小时前
Rust+Slint 实现ModbusRTU从机调试助手源码分享
开发语言·rust·modbusrtu
程序喵大人2 小时前
【C++入门】值类别与表达式 - 03 引用绑定:为什么有些参数能接住临时对象
开发语言·c++·引用绑定
子非鱼a2 小时前
【WEB】[RoarCTF 2019]Easy Java
java·开发语言
软件黑马王子2 小时前
19.资源加载模块:主要作用和基本原理
开发语言·前端框架·c#