首页 > 编程语言 >c++之虚基类

c++之虚基类

时间:2023-03-09 18:11:06浏览次数:54  
标签:调用 基类 c++ class 派生类 之虚 public 构造函数

1.虚基类

在多继承关系中,如果一个派生类的从两个父类那里继承过来,并且这两个父类又恰恰是从一个基类那里继承而来。那这样就麻烦了,因为你可能继承了两份一样的成员!这不仅多占用内存,而且还出现了所谓二义性问题

#include <iostream>
using namespace std;

class Grandfather
{
public:
    int key;
public:
};

class Father1:public Grandfather
{
};
class Father2:public Grandfather
{
};
class Grandson:public Father1,public Father2
{
};
int main() { Grandson A; //A.key=9; return 0; }

定义的四个类都很空,重点看继承关系即可。即Grandson类继承两个father类,会有两个key成员,这个时候如果试图使用这个key,注意已经声明为public类型,在主函数中试图赋值时候,会有“不唯一、模棱两可”的错误提示,即所谓的二义性问题发生

因此,在多重继承中,若希望公共基类在派生类中只有一个拷贝,可将该基类说明为虚基类。即在定义派生类时,在继承的公共基类类名前加上关键字 virtual。那么这个时候,派生类和基类就只维护一份一个基类对象。避免多次拷贝,出现歧义。

class Father1:virtual public Grandfather

class Father2:virtual public Grandfather

2.注意事项

如果派生类继承了多个基类,基类中有虚基类和非虚基类,那么在创建该派生类的对象时,先调用虚基类的构造函数,然后调用非虚基类的构造函数,最后调用派生类的构造函数。若虚基类有多个,则虚基类构造函数的调用顺序取决于它们继承时的说明顺序。

class A {

public:
    int x;
    void SetX(int a) { x = a; }
    A(int a = 0) { x = a; cout << "调用A构造函数" << endl;
    }
    void PA() { cout << "PA" <<x<< endl; }
};
class B :virtual public A {
public:
    int y;
    void SetY(int a) { y = a; }
    B(int a = 0, int b = 0):A(a) { y = b; cout << "调用B构造函数" << endl;
    }
    void PB() { cout << "PB" << "x="<<x<<"y="<<y<<endl; }
};
class C :virtual public A {
public:
    int z;
    void SetZ(int a) { z= a; }
    C(int a = 0, int b = 0) :A(a) { z = b; cout << "调用C构造函数" << endl; }
    void PC() { cout << "PC" <<"x="<<x<<"z="<<z<<endl; }
};
class D :public B, C {
    int m;
public:
    D(int a = 0, int b = 0, int c = 0,int d=0,int e=0):B(a,b),C(c,d) {  m = e; cout << "调用D构造函数" << endl;
    }
    void PD() {  PB();PC();cout<< "x=" << x << "y=" << y << "z=" << z<< endl;
    }
};

int main()
{
D d1(1,2,3,4,5);
d1.PD();
return 0;
}

所以,当基类设置为虚基类时,只拷贝一次虚基类。
但是,为何基类的数据成员x数值为0???
因为类D的构造函数调用了B和C的构造函数,类B和C又调用了类A的构造函数,但是因为由于虚基类在D中只有一个拷贝,编译器无法确定是由B还是C的构造函数调用A的构造函数,所以,编译器约定,执行B和C的构造函数时不调用虚基类A的构造函数,而在类D的构造函数中直接调用A的默认的构造函数。
如果派生类继承了多个基类,基类中有虚基类和非虚基类,那么在创建该派生类的对象时,先调用虚基类的构造函数,然后调用非虚基类的构造函数,最后调用派生类的构造函数。若虚基类有多个,则虚基类构造函数的调用顺序取决于它们继承时的说明顺序。

标签:调用,基类,c++,class,派生类,之虚,public,构造函数
From: https://www.cnblogs.com/david-china/p/17199521.html

相关文章

  • 斯坦福 UE4 C++ ActionRoguelike游戏实例教程 02.AI自定义任务和观察器中断
    斯坦福课程UE4C++ActionRoguelike游戏实例教程0.绪论概述本文章对应课程第十一章42节。这篇文章会进一步地为AI添加新功能,创建自定义任务,允许AI发射子弹,并且讲解观......
  • C++笔记--函数、预处理
    1函数1.1函数的介绍1.1.1函数的概述函数是c语言的功能单位。实现一个功能可以封装一个函数来实现。定义函数的时候一切以功能为目的,根据功能去定函数的参数和返回值......
  • c++11区域锁
    unique_lock方法说明详细说明unique_lock()noexcept;默认构造函数默认构造函数新创建的unique_lock对象不管理任何Mutex对象explicitunique_lock(mut......
  • C++ 三路快排 模板
    前言:今天被大作业的快速排序折磨的焦头烂额,原C++sort选手发现简洁的快排竟然如此难写(边界要注意的点好多qwq)。我原先的快排长这样:题解P1177【【模板】快速排序】......
  • c++常见的几种锁
    std::mutex(C++11),普通互斥锁,可以阻塞式等锁(lock())也可以非阻塞式上锁(try_lock())std::timed_mutex(C++11),互斥锁的加时版本,如果在一段时间内(try_lock_for())或是在某个时间......
  • 【C++】网上购书平台完善
    问题描述收到了一份室友已经完成的网上购书平台程序,对其功能使用和熟悉后,进行了部分功能的添加,使其更加完善。程序概况书店登录界面  部分功能展示    ......
  • c++移动构造函数
    一.介绍1.1 定义【源对象资源的控制权全部移交给目标对象】有些复制构造是必要的,我们确实需要另外一个副本;而有些复制构造是不必要的,我们可能只是希望这个对象换个地方,......
  • c++ 性能分析
    本文记录下日常工作中用到的性能分析工具。一、内存泄漏排查我的服务依赖了jemalloc,这个地方记录下使用jemalloc进行内存分析的方法。1编译jemalloc首先,依赖的je......
  • 【C++】购书系统问题测试&功能补充
    代码来源:舍友大一的C++作业【代码存在的问题】在菜单界面选择对应序号时,若输入值非数字,而是字母等其它符号,会导致程序陷入循环,无法正常进入功能的下一步     ......
  • [Primer] 第 14 章 C++ 中的代码重用
    第14章C++中的代码重用14.1包含对象成员的类类初始化列表中有多个项目时,初始化的顺序为在类中的声明顺序而不是列表顺序。14.2私有继承使用私有继承,基类的所有公......