面向对象编程技术的总结和理解(c++)

目录树

1.继承

1.1 基类成员在派生类中的访问属性

1.2继承时导致的二义性

1.3 多基继承

2.虚函数的多态

2.1虚函数的定义

2.2派生类中可以根据需要对虚函数进行重定义

2.3 虚函数的访问

2.4哪些函数不能定义为虚函数

2.5虚函数表指针(vptr)和虚基类表指针(bptr)

2.5.1 虚函数表指针vptr

2.5.2含静态变量、虚函数的类的空间计算

2.5.3虚基类表指针

2.5.4 虚拟继承时构造函数的书写

2.5.5虚函数

3.运行时类型识别与显示转换

3.1 typeid

3.2 显式转换

1.继承

如果一个类有多个直接基类,而这些直接基类又有一个共同的基类,则在最底层的派生类中会保留这个间接的共同基类数据成员的多份同名成员。提出虚继承,虚继承时,公共基类在对象模型中只有一份拷贝。

1.1 基类成员在派生类中的访问属性

面向对象编程技术的总结和理解(c++)

这里一定要区分清楚派生类对象和派生类中的成员函数对基类的访问时不同的。

1.2继承时导致的二义性

1)在公有继承下(私有,保护继承时,不能隐式转换)下,派生类的对象/对象指针/对象引用可以赋值给基类的对象/对象指针/对象引用(发生隐式转换)。但基类的对象/对象指针/对象引用不能赋值给派生类的对象/对象指针/对象引用。因为派生类包含了基类的所有信息,而基类缺乏派生类中的信息。

2)c++容许把基类的对象指针/对象引用强制转换为(显式)派生类的对象指针/对象引用。

3)一个指向基类的指针可以用来指向该基类公有派生类的任何对象,这是c++实现程序运行时多态性的关键。

1.3 多基继承

当继承基类时,在派生类中就获得了基类所有数据成员的副本,该副本称为子对象。

面向对象编程技术的总结和理解(c++)

2.虚函数的多态

多态是面向对象的精髓。可以概括为一个接口,多种方法。通俗来讲,多态是指同一个操作作用于不同的对象就会产生不同的响应。多态性分为静态多态和动态多态。其中的函数重载和运算符重载属于静态多态。虚函数属于动态多态性。c++是通过虚函数实现动态多态的。

2.1虚函数的定义

虚函数的定义是在函数原型前加一个关键字virtual即可。

如果一个基类成员定义为虚函数,那么,他在所有派生类中也保持为虚函数,即使在派生类中省略了virtual关键字,也任然是虚函数。

2.2派生类中可以根据需要对虚函数进行重定义,重定义的格式要求:

1)与基类的虚函数有相同的参数个数;

2)与基类的虚函数有相同的参数类型;

3)与基类的虚函数有相同的返回类型。或者与基类的虚函数相同,或者返回指针(引用),并且派生类虚函数所返回的指针(引用)类型是基类中被替换的虚函数所返回的指针(引用)类型的子类型(派生类型)。

2.3 虚函数的访问

虚函数可以通过对象名访问,此时编译器采用的是静态编译。

1)通过对象名访问虚函数时,调用哪个类的函数取决于定义对象名的类型。对象类型是基类时,就调用基类的函数。对象类型是子类时就调用子类的函数。

2)使用指针访问非虚函数时,编译器根据指针本身的类型决定要访问那个函数,而不是根据指针指向的对象类型。

3)使用指针访问虚函数时,编译器根据指针所指对象的类型决定要访问那个函数,而不是根据指针本身的类型。

4)使用引用访问虚函数,与使用指针访问虚函数类型,不同的是,引用一经声明,引用变量本身无论如何改变其调用的函数都不会改变,始终指向开始定义时的函数。在一定程序上提高了代码的安全性。(受限制的指针)

总结:
c++中函数调用默认不使用动态绑定,要触发动态绑定需满足两个条件:

a.只用指定为虚函数的成员函数才能进行动态绑定,成员函数默认为非虚函数,非虚函数不能进行动态绑定。

b.必须通过基类类型的引用或指针进行函数调用。

2.4哪些函数不能定义为虚函数

普通函数(类的非成员函数),静态成员函数,构造函数,友员函数。而内联成员函数和赋值操作符重载函数即使声明为虚函数也毫无意义。

2.5虚函数表指针(vptr)和虚基类表指针(bpt r)

2.5.1 虚函数表指针vptr

1)每个类产生一堆指向virtual functions 的指针,放在表格中,这个表格称为虚函数表。

2)每个对象被添加一个指针,指向相关的virtual table,通常这个指针被称为vptr(虚函数表指针)vptr的设定和重置由每一个类的构造函数,析构函数和复制构造函数自动完成。每个类所关联的type_info信息(用以支持rtti)也由virtual table 指出。通常放在表格的第一个slot处。

面向对象编程技术的总结和理解(c++)

2.5.2含静态变量、虚函数的类的空间计算

sizeof应用在类和结构的处理情况是相同的。但是在类中的静态成员不对结构或类的大小产生影响。

2.5.3虚基类表指针

c++支持单一和多重继承。

class iostream:public istream,public ostream{…};

继承关系也可以指定为虚拟(virtual 共享的意思)

class istream :virtual public ios{…};

class ostream :virtual public ios{…}; //菱形继承

面向对象编程技术的总结和理解(c++)

在虚拟继承中,基类不管在继承串链中被派生多少次,永远只会存在一个实体。

在虚拟继承基类的之类中,子类会增加某种形式的指针,或者指向虚基类子对象,或者指向一个相关的表格,表格中存放的不是虚基类子对象的地址,就是其偏移量。此指针叫bptr.

2.5.4 虚拟继承时构造函数的书写

从A类直接虚拟派生(B和C)和间接派生(D)的类中,其构造函数的初始化列表中都要列出对基类A构造函数的调用。这种机制保障不管有多少层继承,虚基类的构造函数必须且只能被调用一次。

若在初始化列表中没有显式调用虚基类的构造函数,则将调用虚基类的默认构造函数。若虚基类没有定义默认构造函数,则编译错误。

2.5.5虚函数

面向对象编程技术的总结和理解(c++)

在基类中不能给出虚函数有意义的实现,而把它声明为纯虚函数,他的实现留给基类的派生类去做。

a.两种常见的抽象类

凡是有纯虚函数 的类叫抽象类(抽象接口),这种类不能声明对象,只是作为基类为派生类服务。除非在派生类中完全实现基类中的所有纯虚函数,否则,派生类也是抽象类,不能实例化对象。

只定义了protected型构造函数的类也是抽象类。对于一个类,如果只定义了protected构造函数而没有提供public构造函数,无论是外部还是派生类中都不能创建该类的对象,但能派生出新类,这种能派生出新类,但不能创建自己对象的类叫另外一种形式的抽象类。

3.运行时类型识别与显示转换

3.1 typeid

c++通过下面两种操作符提供RTTI

1)typeid 操作符,返回指针或引用所指对象的实际类型。

2)dynamic_cast操作符,将基类类型的指针或引用安全的转换为派生类型的指针或引用。

只有当typeid的操作数是带虚函数的类类型的对象时,才返回动态类型信息。

3.2 显式转换

c++中的显式转换也称强制类型转换。包括static_cast、dynamic_cast、 const_cas、 reinterpret_cast。

在引用命名的强制类型转换操作符之前,显式强制类型转换用圆括号将类型括起来实现。

1) reinterpret_cast

int *ip;

char pc=(char) ip;

效果与reinterpret_cast相同。

int *ip;

char *pc=reinterpret_cast

2) const_cast

除了添加和删除const特性,用const_cast符执行其他任何类型转换都会引起编译错误。

3)static_cast

编译器隐式执行的任何类型转换都可以由static_cast显式完成。

只有当类型之间可隐式转换时(除类层次间的下行转化除外),static_cast的转换才是合法的。否则出错。类层次间的下行转化不能通过隐式转换完成。

使用static_cast完成下行转换(把基类指针或引用转换为子类指针或引用),由于没有动态类型检查,所以不安全。

c++的基本类型的指针之间不含隐式转换(除void)需要显示转换。故char 不能隐式转换为int*。

4)dynamic_cast

把expression转换为type类型的对象,type必须是类的指针,类的引用或void*

a.tpye和expression的类型需要一致,都为指针或引用。

与其他转换类型不同,dynamic_cast 涉及运行时类型检查,而这个运行时类型信息存储在类的虚函数表里,只有定义了虚函数的类才有虚函数表,对没有虚函数表的类在使用时会导致dynamic_cast编译错误。如果绑定到引用或指针的对象的类型不是目标类型,则dynamic_cast失败。如果转换到指针类型的dynamic_cast失败,则dynamic_cast的结果为0.如果转换到dynamic_cast失败,则抛出一个bad_cast类型的异常。dynamic_cast操作符执行两个操作。首先验证请求的转换是否有效,操作符执行的验证是在运行时进行的。

b.dynamic_cast主要用于类层次间的上行转换和下行转换

dynamic_cast运算符可以在执行期决定真正的类型。如果下行转换时安全的(基类的指针或引用执行一个派生类对象)这个运算符会传回转型过的指针。如果downcast不安全,这个运算符会传回空指针(基类的指针或引用没有指向一个派生类对象)

在类间进行上行转换时,dynamic_cast和static_cast的效果一样。

在类间进行下行转换时,dynamic_cast具有类型检查功能,比static_cast更加安全。

在运行dynamic_cast时必须包括多态类型。static_cast则没有这个限制。

Original: https://www.cnblogs.com/mydomain/p/10171073.html
Author: 浪里飞
Title: 面向对象编程技术的总结和理解(c++)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/536407/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • EclipseC++学习笔记-1 环境搭建

    最近一个项目使用的EclipseC++编写的,所以需要搭建一个EclipseC++平台开发。1、windows下载https://www.eclipse.org/downloads…

    C++ 2023年5月29日
    071
  • [C++] 浅拷贝和深拷贝

    浅拷贝只是简单的值拷贝; 深拷贝需要重新分配空间。 系统默认的拷贝构造函数属于浅拷贝。 输出结果为: HelloHelloWorldWorld 为什么修改对象 m 的值,对象 n …

    C++ 2023年5月29日
    059
  • c++温故之结构体写法

    结构体简介结构体属于聚合数据类型的一类,它将不同的数据类型整合在一起构成一个新的类型,相当于数据库中一条记录,比如学生结构体,整合了学号,姓名等等信息。结构体的好处就是可以对这些信…

    C++ 2023年5月29日
    082
  • Visual C++ 运行库合集包完整版 v20201209

    Microsoft Visual C++ Redistributable(系统运行库,简称MSVC,VB/VC)是Windows操作系统应用程序的基础类型库组件。 此版Visual…

    C++ 2023年5月29日
    065
  • Embarcadero 发布开源Bloodshed Dev C++ 分支

    Bloodshed Dev C++ 是一个老牌、小巧、快速的开源C++ IDE,它是用delphi 6开发的,从2000年开始 已经被下载过了67,796,885次。是学校、单位学…

    C++ 2023年5月29日
    048
  • [C++] 引用类型&

    引用的方法: 类型 &引用名 = 变量名; 例如: int a = 5; int &b = a; 引用的规则: 1、引用被创建的同时必须被初始化 2、无null引用…

    C++ 2023年5月29日
    051
  • C++20新特性

    conceptrequiresconstinitconstevalco_awaitco_returnco_yieldchar8_t 优点:1)没有头文件;2)声明实现仍然可分离, …

    C++ 2023年5月29日
    060
  • 当C++遇到iOS应用开发—Dict集合

    在Object-c中,字典(KEY/VALUE)使用NSDictionary 和NSMutableDictionary(可变长)。使用语法如下: NSDictionary *dic…

    C++ 2023年5月29日
    050
  • 设置VS2017 来识别其他文件格式为C++文件

    问题:对于其他库中的文件,如.hpp, .ih 往往由于其他库的文件类型撰写风格,需要在Vs2017中能够类似于C++语法来解析这些文件,则需要如下设置: 打开”工具&…

    C++ 2023年5月29日
    042
  • C++自带string类的常用方法

    #include #include<string> using namespace std; int main() { string str1 = "hell…

    C++ 2023年5月29日
    049
  • C#与c++对应的类型

    C#与c++对应的类型 csharp;gutter:true; C#调用C++的DLL搜集整理的所有数据类型转换方式-转载</p> <pre><cod…

    C++ 2023年5月29日
    036
  • Delphi及C++Builder经典图书一览表(持续更新中2018.01.02)

    序号 书名 原版书名 作者 译者 出版社 页数 年代 定价 备注 1 C++Builder 5程序设计大全 C++Builder 5 Developer’s Guide…

    C++ 2023年5月29日
    030
  • C/C++ 回调函数(Callback)& 函数指针

    摘要:回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的…

    C++ 2023年5月29日
    048
  • C++ 借助指针突破访问权限的限制,访问private、protected属性的成员变量(花拳绣腿)

    #include <iostream> using namespace std; class A { public: A(int a, int b, int c); p…

    C++ 2023年5月29日
    050
  • C++ lambda 用法

    为什么要使用lambda 就地匿名的定义一个目标函数或者函数对象,不需要额外的再写一个命名函数或者函数对象,以更直接的方式去写函数,可以调高程序的可读性和可维护性。 简洁:不要额外…

    C++ 2023年5月29日
    058
  • JNI支持C++与C的区别

    C++的代码后缀是”.cpp” 在JNI.h 文件中有两套代码。一套是支持c的, 一套是支持JNI的。 JNI中针对C的代码是: C中调用方式: JNI中针…

    C++ 2023年5月29日
    057
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球