C++速通2

1.作用域限定符::(掌握)

1.1 名字空间

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

using namespace std;

int a = 2;

namespace my_space
{
    int a = 3;
    int b = 4;
}

// 声明名字空间
using namespace my_space;

int main()
{
    int a = 1;
    cout << a << endl;  // 1
    cout << ::a << endl;    // ::表示全局作用域 2
    cout << my_space::a << endl; // 3
    cout << b << endl;  // 4
    return 0;
}
```

1.2 类内声明,类外定义

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

using namespace std;

int a = 2;

namespace my_space
{
    int a = 3;
    int b = 4;
}

// 声明名字空间
using namespace my_space;

int main()
{
    int a = 1;
    cout << a << endl;  // 1
    cout << ::a << endl;    // ::表示全局作用域 2
    cout << my_space::a << endl; // 3
    cout << b << endl;  // 4
    return 0;
}
```

2.this指针(掌握)

2.1 概念

this指针是一个特殊的指针,指向当前类对象的首地址。

成员函数(包括构造函数与析构函数)中都有this指针,因此this指针只能在类内进行使用。实际上this指向的就是当前成员函数所绑定的对象。

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

using namespace std;

int a = 2;

namespace my_space
{
    int a = 3;
    int b = 4;
}

// 声明名字空间
using namespace my_space;

int main()
{
    int a = 1;
    cout << a << endl;  // 1
    cout << ::a << endl;    // ::表示全局作用域 2
    cout << my_space::a << endl; // 3
    cout << b << endl;  // 4
    return 0;
}
```

2.2 功能

2.2.1 类内调用成员

成员(成员变量+成员函数),必须由对象调用。类中成员的调用都依赖于this指针。通常由编译器自动添加。

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

using namespace std;

int a = 2;

namespace my_space
{
    int a = 3;
    int b = 4;
}

// 声明名字空间
using namespace my_space;

int main()
{
    int a = 1;
    cout << a << endl;  // 1
    cout << ::a << endl;    // ::表示全局作用域 2
    cout << my_space::a << endl; // 3
    cout << b << endl;  // 4
    return 0;
}
```

2.2.2 区分重名的成员变量与局部变量

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

using namespace std;

int a = 2;

namespace my_space
{
    int a = 3;
    int b = 4;
}

// 声明名字空间
using namespace my_space;

int main()
{
    int a = 1;
    cout << a << endl;  // 1
    cout << ::a << endl;    // ::表示全局作用域 2
    cout << my_space::a << endl; // 3
    cout << b << endl;  // 4
    return 0;
}
```

3.stactic关键字(掌握)

3.1 静态成员变量

静态成员变量,需要类内声明,类外定义。

一个类的所有对象共用一份静态成员变量。

静态成员变量虽然可以通过对象进行调用,但是更建议直接使用类名加作用域的方式进行调用。(更推荐使用类名::的方式调用,因为代码可读性更好)

在程序开始运行时就开辟空间了,直接程序运行结束后进行销毁。

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

using namespace std;

int a = 2;

namespace my_space
{
    int a = 3;
    int b = 4;
}

// 声明名字空间
using namespace my_space;

int main()
{
    int a = 1;
    cout << a << endl;  // 1
    cout << ::a << endl;    // ::表示全局作用域 2
    cout << my_space::a << endl; // 3
    cout << b << endl;  // 4
    return 0;
}
```

3.2 静态成员函数

使用static修饰的成员函数,这样的函数就是静态成员函数

静态成员函数可以通过类名::的方式调用(更推荐使用类名::的方式)

静态成员函数中,没有this指针,因此不能在静态成员函数中调用同类其他的非静态成员。

静态成员函数可以调用当前的静态成员

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

using namespace std;

int a = 2;

namespace my_space
{
    int a = 3;
    int b = 4;
}

// 声明名字空间
using namespace my_space;

int main()
{
    int a = 1;
    cout << a << endl;  // 1
    cout << ::a << endl;    // ::表示全局作用域 2
    cout << my_space::a << endl; // 3
    cout << b << endl;  // 4
    return 0;
}
```

4.const关键字(掌握)

4.1const修饰成员函数

  • 常成员函数,对于当前类的普通成员变量,可以访问,但是不能修改
  • 对于当前类的普通成员函数,无法访问
  • 常成员函数可以访问常成员函数
cpp 复制代码
```cpp
#include <iostream>

using namespace std;

int a = 2;

namespace my_space
{
    int a = 3;
    int b = 4;
}

// 声明名字空间
using namespace my_space;

int main()
{
    int a = 1;
    cout << a << endl;  // 1
    cout << ::a << endl;    // ::表示全局作用域 2
    cout << my_space::a << endl; // 3
    cout << b << endl;  // 4
    return 0;
}
```

5.继承(重点)

5.1 概念

继承是面向对象的三大特性之一,体现了代码复用的思想。

继承就是在一个已经存在的类的基础上建立一个新的类,并拥有其特性。

  • 已经存在的类被称为"基类"或者"父类"
  • 新建立的类被称为"派生类"或者"子类"
cpp 复制代码
```cpp
#include <iostream>

using namespace std;

int a = 2;

namespace my_space
{
    int a = 3;
    int b = 4;
}

// 声明名字空间
using namespace my_space;

int main()
{
    int a = 1;
    cout << a << endl;  // 1
    cout << ::a << endl;    // ::表示全局作用域 2
    cout << my_space::a << endl; // 3
    cout << b << endl;  // 4
    return 0;
}
```

在继承结构中,派生类往往会做出一些与基类的差异化。

修改继承下来的内容

属性:公有属性可以直接修改。私有属性,派生类中无法访问和修改

行为:函数,函数隐藏。通过派生类实现一个与基类函数同名函数,来隐藏基类同名函数。

新增派生类的内容

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

using namespace std;

int a = 2;

namespace my_space
{
    int a = 3;
    int b = 4;
}

// 声明名字空间
using namespace my_space;

int main()
{
    int a = 1;
    cout << a << endl;  // 1
    cout << ::a << endl;    // ::表示全局作用域 2
    cout << my_space::a << endl; // 3
    cout << b << endl;  // 4
    return 0;
}
```

5.2 构造函数

5.2.1 派生类与基类构造函数的关系

构造函数与析构函数不能被继承。

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

using namespace std;

int a = 2;

namespace my_space
{
    int a = 3;
    int b = 4;
}

// 声明名字空间
using namespace my_space;

int main()
{
    int a = 1;
    cout << a << endl;  // 1
    cout << ::a << endl;    // ::表示全局作用域 2
    cout << my_space::a << endl; // 3
    cout << b << endl;  // 4
    return 0;
}
```

派生类的任意一个构造函数,都必须直接或间接调用基类的任意一个构造函数

5.2.2 解决方案

5.2.2.1 补充基类的无构造参数
cpp 复制代码
#include <iostream>

using namespace std;

class Father
{
private:
    string name;
public:
    // 有参构造函数
    Father(string name)
        :name(name){}

    // 无参构造函数
    Father()
    {
        name = "张三";
    }

    string get_name()
    {
        return name;
    }
};

class Son : public Father
{

};

int main()
{
    Son s1;
    cout << s1.get_name() << endl;
//    Son s2("hello"); // 错误 找不到派生类的有参构造函数

    return 0;
}
5.2.2.2 透传构造

在派生类的构造函数中,调用基类的构造函数。实际上编译器自动添加的派生类调用基类无构造参数函数时,就是采用的透传构造。

cpp 复制代码
#include <iostream>

using namespace std;

class Father
{
private:
    string name;
public:
    // 有参构造函数
    Father(string name)
        :name(name){}

    // 无参构造函数
    Father()
    {
        name = "张三";
    }

    string get_name()
    {
        return name;
    }
};

class Son : public Father
{
public:
    // 透传构造
    // 调用基类的无参构造函数
    Son():Father(){}
    // 调用基类的有参构造函数
//    Son():Father("李四"){}

//    Son(string name):Father(){}
    Son(string name):Father(name){}
};

int main()
{
    Son s1;
    cout << s1.get_name() << endl;
    Son s2("hello"); // 错误 找不到派生类的有参构造函数
    cout << s2.get_name() << endl;
    return 0;
}

6. 权限(掌握)

6.1 权限修饰符

三种权限一共对应了九种场景,要做到心中有表,遇到任何一种场景都能够直接反应出来是否能够访问。

|-----------|----|------|----|
| | 类内 | 派生类中 | 全局 |
| private | √ | × | × |
| protected | √ | √ | × |
| public | √ | √ | √ |

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

using namespace std;

class Base
{
protected:
    string s = "保护权限";
public:
    Base()
    {
        cout << s << endl;
    }
};

class Son : public Base
{
public:
    Son()
    {
        cout << s << endl;
    }
};

int main()
{
    Son s1;
//    s1.s; // 错误s是保护权限

    return 0;
}
```

6.2 不同权限的继承(熟悉)

6.2.1 公有继承

之前的代码中一直使用的就是公有继承。公有继承也是所有继承方式中使用最多的一种方式。

在公有继承中,派生类会继承基类的成员,不可以访问基类的私有成员,基类的保护成员与公有成员,在派生类中可以访问。基类继承下来的内容,权限在派生类中保持不变。

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

using namespace std;

class Base
{
private:
    string str1 = "私有成员";
protected:
    string str2 = "保护成员";
public:
    string str3 = "公有成员";

};

class Son : public Base
{
public:
    Son()
    {
//        cout << str1 << endl; // 错误str1为私有成员,派生类中无法访问
        cout << str2 << endl;
        cout << str3 << endl;
    }
};


int main()
{
    Son s1;
//    s1.str1;  // 类外无法访问
//    s1.str2;  // 类外无法访问
    s1.str3;

    return 0;
}
```

6.2.2 保护继承

在保护继承中,派生类可以继承基类的成员。

不可以访问基类的私有成员。

基类的公有成员在派生类中为保护权限,其他权限的成员,保持权限不变。

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

using namespace std;

class Base
{
private:
    string str1 = "私有成员";
protected:
    string str2 = "保护成员";
public:
    string str3 = "公有成员";

};

class Son : protected Base
{
public:
    Son()
    {
//        cout << str1 << endl; // 错误str1为私有成员,派生类中无法访问
        cout << str2 << endl;
        cout << str3 << endl;
    }
};


int main()
{
    Son s1;
//    s1.str1;  // 类外无法访问
//    s1.str2;  // 类外无法访问
//    s1.str3;  // 类外无法访问

    return 0;
}
```

6.2.3 私有继承

在私有继承中,派生可以继承基类的成员。

但是不可以访问基类的私有成员。

基类的公有成员与保护成员在派生类中都为私有权限。

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

using namespace std;

class Base
{
private:
    string str1 = "私有成员";
protected:
    string str2 = "保护成员";
public:
    string str3 = "公有成员";

};

class Son : private Base
{

public:
    Son()
    {
//        cout << str1 << endl; // 错误str1为私有成员,派生类中无法访问
        cout << str2 << endl;
        cout << str3 << endl;
    }
};


int main()
{
    Son s1;
//    s1.str1;  // 类外无法访问
//    s1.str2;  // 类外无法访问
//    s1.str3;  // 类外无法访问

    return 0;
}
```

7.多态(重点)

7.1 概念

多态可以理解为"一种接口,多种状态",只需要编写一个函数接口,根据传入的参数类型,执行不同的策略代码。

多态的实现需要有三个前提条件:

公有继承

函数覆盖

基类的指针或者引用指向派生类对象

多态的优点:多态的优势包括代码的灵活性、可扩展和可维护性。它能够使代码更具有通用性,减少重复代码的编写,并且能够轻松添加新的派生类或扩展现有功能。

多态的缺点:多态的缺点包括代码的复杂性、运行效率、易读性。当类的继承关系复杂时,理解和维护多态性相关的代码会变得困难。多态在运行中会产生一些额外的开销。

7.2 函数的覆盖

函数的覆盖、函数隐藏,函数隐藏不支持多态,函数覆盖是多态的必要条件。

函数隐藏:派生类中定义了一个与基类同名的函数,编译器会将基类中所有同名的函数进行隐藏。

函数覆盖:基类中定义了一个虚函数,派生类编写了一个同名同参的函数,将基类中同名同参的虚函数进行隐藏。

7.3 虚函数的定义

一个函数使用virtual关键字修饰,就是虚函数,虚函数是函数覆盖的前提。在QtCreator中使用斜体字。

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

using namespace std;

class Animal
{
public:
    // 虚函数
    virtual void eat()
    {
        cout << "动物爱吃饭" << endl;
    }

};

int main()
{


    return 0;
}
```

虚函数具有以下的潜质:

虚函数具有传递性,基类中被覆盖的函数是虚函数,派生类中覆盖的函数也是虚函数。

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

using namespace std;

class Animal
{
public:
    // 虚函数
    virtual void eat()
    {
        cout << "动物爱吃饭" << endl;
    }
};

class Dog : public Animal
{
public:
    // 覆盖基类中的虚函数,派生类virtual可写可不写
    void eat()
    {
        cout << "狗爱吃骨头" << endl;
    }
};

int main()
{


    return 0;
}
```

只有普通成员函数与析构函数可以声明虚函数。

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

using namespace std;

class Animal
{
public:
    // 虚函数
    virtual void eat()
    {
        cout << "动物爱吃饭" << endl;
    }
};

class Dog : public Animal
{
public:
    // 覆盖基类中的虚函数,派生类virtual可写可不写
    void eat()
    {
        cout << "狗爱吃骨头" << endl;
    }
};

int main()
{


    return 0;
}
```

7.4 多态的实现

要是实现多态,需要有三个前提条件:

公有继承

函数覆盖

基类的指针或者引用,指向派生类对象

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

using namespace std;

class Animal
{
public:
    // 虚函数
    virtual void eat()
    {
        cout << "动物爱吃饭" << endl;
    }

};

class Dog : public Animal
{
public:
    // 覆盖基类中的虚函数,派生类virtual可写可不写
    void eat()
    {
        cout << "狗爱吃骨头" << endl;
    }
};

int main()
{
    // 基类的指针指向派生类对象
    Animal *a1 = new Dog;
    a1->eat();  // 狗爱吃骨头

    // 基类的引用给派生类起别名
    Dog d1;
    Animal &d2 = d1;
    d2.eat();   // 狗爱吃骨头

    return 0;
}
```
cpp 复制代码
```cpp
#include <iostream>

using namespace std;

class Animal
{
public:
    // 虚函数
    virtual void eat()
    {
        cout << "动物爱吃饭" << endl;
    }

};

class Dog : public Animal
{
public:
    // 覆盖基类中的虚函数,派生类virtual可写可不写
    void eat()
    {
        cout << "狗爱吃骨头" << endl;
    }
};

int main()
{
    // 基类的指针指向派生类对象
    Animal *a1 = new Dog;
    a1->eat();  // 狗爱吃骨头

    // 基类的引用给派生类起别名
    Dog d1;
    Animal &d2 = d1;
    d2.eat();   // 狗爱吃骨头

    return 0;
}
```

7.2 多态的原理(熟悉)

具有虚函数的类会存在一张虚函数表。每个类的对象内部,会有一个隐藏的虚函数表指针成员,指向当前类的虚函数表。

在代码运行时,通过对象的虚函数表指针找到虚函数表,在表中定位到虚函数的调用地址,从而执行对应的虚函数内容。

8.虚析构函数

当基类的指针指向派生类对象时,delete销毁对象时,只能触发基类的析构函数。派生类内存空间出现泄露的问题。

这种情况需要使用析构函数,来解决。

因此我们建议,把每一个可能为基类的类,它的析构函数都声明为析构函数。

cpp 复制代码
#include <iostream>

using namespace std;

class Animal
{
public:
    virtual ~Animal()
    {
        cout << "Animal 析构函数被调用了" << endl;
    }
};

class Dog : public Animal
{
public:
    ~Dog()
    {
        cout << "Dog的析构函数" << endl;
    }
};


int main()
{
    Animal *a1 = new Dog;
    delete a1;

    return 0;
}
相关推荐
CarIise1 小时前
C语言字符串基础:从char数组到双指针反转算法
算法
似水এ᭄往昔1 小时前
【Qt】--常用控件(输入类控件)
开发语言·qt
David猪大卫1 小时前
【C++修炼】异常
开发语言·c++·经验分享·笔记·学习·考研·面试
麻瓜code1 小时前
【LeetCode】相交链表:双指针法,一次遍历找到交点
算法·leetcode·链表
玖玥拾1 小时前
Lua 基础语法(六)xLua Lua 调用 C# 交互
开发语言·unity·c#·lua
Joolun商城源码_Java1 小时前
Java 商城技术栈怎么选:单体、微服务还是前后端分离多端?
java·开发语言·微服务
charlie1145141911 小时前
浅谈C++的列表初始化std::initializer_list
开发语言·数据结构·c++·list·开源项目
拒绝内耗。2 小时前
一个请求进入 Java 应用后,怎么找到我们写的方法?
java·开发语言
励志不掉头发的内向程序员2 小时前
【LibreCAD 2D架构】RS_Line创建之后发生了什么?从图形容器到屏幕渲染
开发语言·c++·qt·学习·系统架构