IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++类与虚函数 -> 正文阅读

[C++知识库]C++类与虚函数


一、 类

类成员属性

C++通过 publicprotectprivate 三个关键字来控制成员变量和成员函数的访问权限。

成员访问权限:

  • public: 在类内部可以互相访问,没有权限限制,在类外可以通过实例化对象进行访问。
  • protect: 在类内部可以互相访问,没有权限限制。在类外无法通过实例化对象访问累得protect成员,但可以通过友元函数和友元类进行访问。
  • private: 在类内部可以互相访问,没有权限限制。在类外无法通过实例化对象访问累得protect成员,但可以通过友元函数和友元类进行访问。

继承访问权限:

  • public继承

    子类的成员函数可以访问父类的public、protect成员,但无法访问父类的private成员
    子类的实例对象可以访问父类的public成员,但无法访问protect、private成员

  • protect继承

    通过protect继承,父类的public成员在子类中的权限变为protect,其余的不变
    子类的成员函数可以访问父类的public、protect成员,但无法访问父类的private成员
    子类的实例对象无法访问任何父类成员,因为父类的public成员在子类中已经变成了protect

  • private继承

    通过private继承,父类中的所有成员在子类中权限都变为private
    子类的成员函数可以访问父类的public、protect成员,但无法访问父类的private成员
    子类的实例对象无法访问任何父类成员,因为父类的public成员在子类中已经变成了private

构造函数和析构函数

  1. 构造函数

    类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。

  2. 带参数的构造函数

    默认的构造函数是不带参数的,如果需要用到含参构造函数可以通过重载 实现。含参构造函数 可以在实例化对象的时候同时给类成员赋初始值。

    C++类内如需定义引用数据成员需要通过含参构造函数初始化列表初始化。

    #include<iostream>
    
    class A
    {
     public:
        int &a;
        A(&b):a(b){}
    };
    int main()
    {
        int b = 21;
        A demo(b);
        std::cout<<demo.a<<'\n';
        return 0;
    }
    
  3. 拷贝构造函数

    拷贝构造函数只有一个参数,就是当前类的实例化对象的引用。如果类的设计者不写拷贝构造函数则编译器会自动生成一个默认拷贝构造函数 其作用是实现从源对象到目标对象逐个字节的复制。拷贝构造函数的参数可以是 const引用也可以是非const引用,甚至可以在一个类中写两个拷贝构造函数,但是参数必须是对象的引用

    Q: 拷贝构造函数为什么不能直接进行值传递而必须用引用呢?

    A: 如果直接使用值传递的话,在调用拷贝构造函数的时候,会自动生成一个临时对象保存传进来的实参并将其传给形参,在这个过程中有需要调用拷贝构造函数,如此一来就会形成循环调用,最终不但无法完成拷贝,还会造成栈溢出。

  4. 析构函数

    析构函数是一种特殊的成员函数,其名字与类名相同,没有参数和返回值,通过在名字前加一个**“~”** 取反符号声明。一个类可以拥有多个构造函数,但是有且仅有一个析构函数 。析构函数会在对象消亡的时候自动调用,用以在撤销对象占用的内存空间前做一些善后工作。如果类的设计者不写析构函数,编译器会自动生成一个缺省的析构函数,这个析构函数什么也不做。

  • 构造函数和析构函数调用顺序

    • 构造函数调用顺序:父类的构造函数 -> 对象成员的构造函数 -> 子类的构造函数

    • 析构函数调用顺序:子类的析构函数 -> 对象成员的析构函数 -> 父类的析构函数

      先构造后析构 (有点类似栈的思想了…)

空类大小

class A{}; //这个空类大小会是0吗?

C++并不允许一个类的大小为0,我们假设一个空类大小为0,当我们用这个类去实例化很多对象的时候,这些对象大小都是0,对应内存中的地址也是一样的,那我们用什么区分这些不同的对象呢?所以为了区分不同的空类实例化对象,编译器会往空类里面隐式的添加一定大小的字节信息,这个大小由编译器决定,在VS下是1个字节.


二、 虚函数

虚函数由 virtual 关键字声明,是实现C++多态的重要手段。虚函数只能借助于指针或者引用来达到多态的效果,直接声明的类对象无法达到多态的目的。虚函数的调用值取决于指针或引用所 指向的对象的类型 ,而与指针本身的类型无关。比如父类指针指向子类对象,调用的是子类重写后的虚函数

虚函数实现多态主要通过虚函数表vtable 和虚表指针 vptr 实现。

虚函数表和虚表指针

  • 在拥有虚函数的类中,类的最开始部分是一个虚表指针,这个指针指向该类的一个虚函数表,表中存放的该类中虚函数的地址,实际的虚函数代码存放在内存中的text段中。如果子类继承了父类,那么就会同时继承父类的虚函数表,如果子类对父类中定义的虚函数进行了重写,那么其继承的虚函数表中相应的虚函数地址就会被替换成重写之后的虚函数的地址。

  • 使用了虚函数,会增加内存的开销,降低效率,因此对于不会被继承的类,不会为其声明虚函数,这也是为什么默认的析构函数不是虚函数 的原因。

  • 对于拥有虚函数的类,编译器都会为其添加一个隐式的虚表指针成员,故拥有虚函数的类sizeof 大小至少都为4(一个指针的大小)

析构函数与虚函数

当一个类有可能会被其他类继承的时候,就应该将此类的析构函数声明为虚函数,这么做可以保证当我们释放一个指向子类的父类指针时可以释放子类的内存,以免出现内存泄漏。

纯虚函数和抽象类

  • 纯虚函数: 在父类中只声明不定义并要求其每个子类都进行重写的虚函数。纯虚函数为所有继承它的子类提供了一个可重写的接口,但父类的这个版本绝不会被调用。在父类中纯虚函数的声明方法就是在函数原型后面加 “=0”
  • 抽象类: 拥有纯虚函数的类即为抽象类。 抽象类不能实例化对象!

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-31 16:26:28  更:2021-07-31 16:28:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/27 13:54:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码