虚基类

c++第五次博客作业

本小妞迷上赌 提交于 2019-12-02 11:04:53
       C++虚函数,纯虚函数,抽象类以及虚基类的区别   Part1.C++中的虚函数 什么是虚函数: 直观表达就是,如果一个函数的声明中有 virtual 关键字,那么这个函数就是虚函数。 虚函数的作用: 虚函数的最大作用就是实现面向对象程序设计的一大特点,多态性,多态性表达的是一种动态的概念,是在函数调用期间,进行动态绑定,以达到什么样的对象就实现什么样的功能的效果。 虚函数的一般声明语法: virtual 函数类型 函数名 (形参表) 注意: 虚函数的声明只能出现在类的定义中,不能出现在成员函数实现的时候 虚函数一般不声明为内联函数,但是声明为内联函数也不会引起错误 在运行过程中要实现多态的三个条件: 类之间满足赋值兼容关系(也就是类之间有继承关系) 要声明为虚函数 调用虚函数时,要由成员函数或者是指针和引用来访问 代码举例 #include <iostream> using namespace std; class Base1 { public: public: virtual void play(); }; void Base1::play() { cout << "Base1::play()" << endl; } class Base2: public Base1 { virtual void play(); }; void Base2::play() {

空类,含有虚函数的类的大小

自作多情 提交于 2019-12-01 10:18:55
1、为何空类的大小不是0呢? 为了确保两个不同对象的地址不同,必须如此。 类的实例化是在内存中分配一块地址,每个实例都有独一无二的内存地址。空类也会实例化,为保证空类实例化后的独一无二性,编译器会给空类隐含的添加一个字节。所以,空类的sizeof为1,而不是0. 2、继承关系中的类大小: case 1: 父类有虚函数,子类继承。 class A{ virtual void f(){} }; class B:public A{} 此时,类A和类B都不是空类,其sizeof都是4,因为它们都具有虚函数表的地址。 case 2: 父类是空类,子类以虚基类方式继承。 class A{}; class B:public virtual A{}; 此时,A是空类,其大小为1;B不是空类,其大小为4.因为含有指向虚基类的指针。 case 3: 多重空类继承 class Father1{}; class Father2{}; class Child:Father1, Father2{}; 它们的sizeof都是1. 5、何时共享虚函数地址表: 如果派生类继承的第一个是基类,且该基类定义了虚函数地址表,则派生类就共享该表首址占用的存储单元。对于除前述情形以外的其他任何情形,派生类在处理完所有基类或虚基类后,根据派生类是否建立了虚函数地址表,确定是否为该表首址分配存储单元。 来源: https:/

类的继承和派生

我的未来我决定 提交于 2019-12-01 07:20:19
类的继承和派生 格式: class 派生类名:继承方式 基类名, 继承方式 基类名.... { 类体 } 继承形式多种多样: 继承会把基类的所有成员均继承 graph LR A类-->B A类-->C graph LR A类-->B类 B类-->C类 graph LR A类-->B类 B类-->C类 A类-->D类 D类-->C类 继承方式有:public, protected, privated 对于继承来的基类是把基类所有成员(除开基类的构造函数与析构函数)都继承了的,仅是对于访问权限的不同. 一般说来基类的私有成员,派生类是无法直接访问的,任何继承方式都是这样 public:基类的public和protected在派生类中依旧是public和privated,但是基类的privated在派生类中将无法直接访问(可用继承的基类函数对这些私有成员访问进行操作) protected:基类的public和protected在派生类中变成protected,基类的privated在派生类中将无法直接访问 privated:基类的public和protected在派生类中变成privated,基类的privated在派生类中将无法直接访问 类的派生: 除开继承来的东西还加入了直接的特性 类的类型兼容 类的类型兼容 #include using namespace std; class

嵌入式C++测试题

早过忘川 提交于 2019-11-30 10:30:18
仅供学习,为嵌入式帝国做亿分之一的贡献吧,临近国庆,祝大家国庆节快乐哦 答案仅供参考吧 一、 选择题(共 80 分, 每题 2 分 ) ( 1 ) A ( 2 ) C ( 3 ) C ( 4 ) B ( 5 ) D ( 6 ) C ( 7 ) C ( 8 ) D ( 9 ) A ( 10 ) C ( 11 ) A (12) B (13) D (14) B (15) A ( 16 ) A ( 17 ) C ( 18 ) D ( 19 ) D ( 20 ) C ( 21 ) C ( 22 ) D ( 23 ) D ( 24 ) D ( 25 ) A ( 26 ) C (27) C (28) C (29) B (30) B ( 31 ) A ( 32 ) D ( 33 ) D ( 34 ) B ( 35 ) A ( 36 ) A ( 37 ) B ( 38 ) B ( 39 ) C ( 40 ) C 二、 填空题(每空 1 分, 共 20 分) 1. 构造函数 2. friend 保护和私有成员 3. 先基类在派生类 4. 单一继承 5. virtual 6. 静态多态性 动态多态性 7. 抽象类 8. 测试是否文件尾 9. 成员函数 10. try throw catch 11. 代码复用和泛型程序设计 12. 类的友元函数 13. 抛出异常 捕捉异常 14. template 15.

C++对象模型:单继承,多继承,虚继承,菱形虚继承,及其内存布局图

放肆的年华 提交于 2019-11-29 22:02:48
C++目前使用的对象模型: 此模型下, nonstatic数据成员被置于每一个类的对象中 ,而 static数据成员则被置于类对象之外 , static和nonstatic函数也都放在类对象之外(通过函数指针指向) ,而 对于virtual函数,则通过虚函数表+虚函数指针来支持 : 1)每个类生成一个表格,称为 虚表 (virtual table,简称vtbl),虚函数表中存在一堆指针,这些指针指向该类的每一个虚函数,虚表中的函数地址按照声明时的顺序排列 2)每个类对象都有一个 虚表指针 (简称vptr),由编译器为其生成,虚表指针的设定和重置皆由类的相关函数控制(构造函数,析构函数,赋值操作符),虚表指针vptr的位置由编译器决定,一般编译器把vptr放在一个类对象的最前端(也就是说对象的地址就是vptr的地址) 3)虚函数表的前面设置了一个指向type-info的指针,用以支持RTTI(Run Time Type Identification,运行时类型识别),RTTI是为支持多态生成的信息,包括对象的继承关系,对象本身的描述等,只有具有虚函数的对象才会生成 样例: class Base { public: Base(int i) :baseI(i){}; int getI(){ return baseI; } static void countI(){}; virtual

虚继承

。_饼干妹妹 提交于 2019-11-29 01:43:55
  尽管在派生列表中同一个基类只能出现一次,但实际上派生类可以多次继承同一个类。派生类可以通过它的两个直接基类分别继承同一个间接基类,也可以直接继承某个基类,然后通过另一个基类再一次间接继承该类。   举个例子,IO标准库的istream和ostream分别继承了一个共同的名为base_ios的抽象基类。该抽象基类负责保存流的缓冲内容并管理流的条件状态。iostream是另外一个类,它从istream和ostream直接继承而来,可以同时读写流的内容。因为istream和ostream都继承自base_ios,所以iostream继承了base_is两次,一次是通过istream,另一次是通过ostream。   在默认情况下,派生类中含有继承链上每个类对应的子部分。如果某个类在派生过程中出现了多次,则派生类中将包含该类的多个子对象。   这种默认的情况对某些形如iostream的类显然是行不通的。一个iostream对象肯定是希望在同一个缓冲区进行读写操作,也会要求条件状态能同时反映输入和输出操作的情况。假如在iostram对象中真的包含了base_ios的两份拷贝,则上述的共享行为就无法实现而了。    在C++语言中我们通过虚继承(virtual inheritance)的机制解决上述问题。虚继承的目的是令某个类做出声明,承诺愿意共享它的基类。其中,共享的基类子对象成为虚基类

虚继承和虚基类

南楼画角 提交于 2019-11-27 10:37:39
多继承(Multiple Inheri tan ce)是指从多个直接基类中产生派生类的能力,多继承的派生类继承了所有父类的成员。尽管概念上非常简单,但是多个基类的相互交织可能会带来错综复杂的设计问题,命名冲突就是不可回避的一个。 多继承时很容易产生命名冲突,即使我们很小心地将所有类中的成员变量和成员函数都命名为不同的名字,命名冲突依然有可能发生,比如典型的是菱形继承,如下图所示: 图1:菱形继承 类 A 派生出类 B 和类 C,类 D 继承自类 B 和类 C,这个时候类 A 中的成员变量和成员函数继承到类 D 中变成了两份,一份来自 A-->B-->D 这条路径,另一份来自 A-->C-->D 这条路径。 在一个派生类中保留间接基类的多份同名成员,虽然可以在不同的成员变量中分别存放不同的数据,但大多数情况下这是多余的:因为保留多份成员变量不仅占用较多的存储空间,还容易产生命名冲突。假如类 A 有一个成员变量 a,那么在类 D 中直接访问 a 就会产生歧义,编译器不知道它究竟来自 A -->B-->D 这条路径,还是来自 A-->C-->D 这条路径。下面是菱形继承的具体实现: 复制纯文本复制 //间接基类Aclass A{protected: int m_a;}; //直接基类Bclass B: public A{protected: int m_b;}; //直接基类Cclass

构造函数,复制构造函数,析构函数

大兔子大兔子 提交于 2019-11-27 03:38:56
构造函数: 创建对象时利用特定的值构造对象,将对象初始化为一个特定的状态。 构造函数的函数名与类名相同,且没有返回值。通常被声明为公有函数。 默认构造函数:如果没有声明构造函数时,编译器自动生成一个无参的构造函数。 函数体为空的构造函数并非什么都不做,因为它还要负责基类的构造和成员对象的构造。 构造函数的执行顺序: 如果该类存在虚基类,则先调用虚基类的构造函数完成对虚基类成员的初始化。(虚基类) 如果该类存在其他基类,则按照在继承声明列表中出现的次序,分别执行它们的构造函数,但构造过程中不再执行他们的虚基类的构造函数。(派生类) 按照在类定义中出现的次序,对新增成员对象进行初始化。对于类类型的成员对象,如果出现在构造函数初始化列表中,则以其中指定的参数执行构造函数。如果未出现在初始化列表中,则执行默认构造函数。对于其他基本数据类型的成员,如果出现在初始化列表中,则按照其指定的参数初始化。如果未出现在初始化列表中,则什么也不做。(组合类) 执行构造函数体。 复制构造函数: 特殊的构造函数。形参为本类对象的引用。作用是使用已经存在的本类对象,初始化同类的一个新对象。 没有声明复制构造函数时, 编译器自动生成一个隐含的复制构造函数。完成数据成员的copy。 调用场景: 用类的一个对象去初始化该类的另一个对象时。 Point a(1,2); 调用构造函数 Point b(a);