当前位置: 首页 > news >正文

C++虚继承及其它特性

一、其它特性

1、冲突

示例:

#include <iostream>
using namespace std;

class A
{
public:
	int x;
	void print()
	{
		cout << "调用类A的print()函数.\n";
		cout << "x=" << x << endl;
	}
};

class B
{
public:
	int y;
	void print()
	{
		cout << "调用类B的print()函数.\n";
		cout << "y=" << y << endl;
	}
};

class C:public A,public B
{
public:
	int y;  // 类B的和类C均有y的数据成员	
};

int main()
{
	C c1;
	c1.x = 100;
	c1.y = 200;  // 未指明的情况下,给派生类中的y赋值
	c1.B::y = 300; // 给基类B的y赋值

	c1.A::print();
	c1.B::print();

	cout << "y=" << c1.y << endl;  // 输出派生类中的y的值
	cout << "y=" << c1.B::y << endl; // 输出基类B中的y的值

	return 0;
}

在这里插入图片描述

2、支配原则

       当派生类中新增加的数据或函数与基类中原有的同名时,若不加限制,则优先调用派生类中的成员

3、基类与对象成员

       任一基类在派生类中只能继承一次,否则,会造成成员名的冲突;
       若在派生类中,确实要有二个以上基类的成员,则可用基类的二个对象作为派生类的成员
       把一个类作为派生类的基类或把一个类的对象作为一个类的成员,在使用上是有区别的:在派生类中可直接使用基类的成员(访问权限允许的话),但要使用对象成员的成员时,必须在对象名后加上成员运算符“.”和成员名

示例:

class Derived {
private:
    Base1 b1; // Base1 的对象
    Base2 b2; // Base2 的对象
public:
    void show() {
        b1.display(); // 使用对象调用 Base1 的 display()
        b2.display(); // 使用对象调用 Base2 的 display()
    }
};

4、赋值兼容规则

       可以将派生类对象的值赋给基类对象。反之不行。只是将从基类继承来的成员赋值

  • 可以将一个派生类对象的地址赋给基类的指针变量。

  • basep只能引用从基类继承来的成员。

二、虚继承

类B 是类A的派生类
类C 是类A的派生类
类D 是类B和类C的派生类 这样,类D中就有两份类A的拷贝

在这里插入图片描述
       这种同一个公共的基类在派生类中产生多个拷贝,不仅多占用了存储空间,而且可能会造成多个拷贝中的数据不一致和模糊的引用

       在多重派生的过程中,若使公共基类在派生类中只有一个拷贝,则可将这种基类说明为虚基类。在派生类的定义中,只要在基类的类名前加上关键字virtual,就可以将基类说明为虚基类。

       由虚基类派生出的对象初始化时,直接调用虚基类的构造函数。因此,若将一个类定义为虚基类,则一定有正确的构造函数可供所有派生类调用。

       再次强调,用虚基类进行多重派生时,若虚基类没有缺省的构造函数,则在每一个派生类的构造函数中都必须有对虚基类构造函数的调用 (且首先调用)。

示例:

#include <iostream>
using namespace std;

class A {
public:
	int x;
	A(int a = 0)
	{
		cout << "调用类A:构造函数." << endl;
		x = a;
	}
};

class B : virtual public A {
public:
	int y;
	B(int a = 0, int b = 0) :A(a) {
		cout << "调用类B:构造函数." << endl;
		y = b;
	}
};
class C :virtual public A {
public:
	int z;
	C(int a = 0, int c = 0) :A(a) {
		cout << "调用类C:构造函数." << endl;
		z = c;
	}
};

class D :public B, public C
{
public:
	int dx;
	D(int a1, int b, int c, int d, int a2) :B(a1, b), C(a2, c)
	{
		cout << "调用类D:构造函数." << endl;
		dx = d;
	}
};

int main()
{
	D obj(100, 200, 300, 400, 500);

	cout << "\nobj.x=" << obj.x << endl;
	obj.x = 20000;

	cout << obj.x << endl;
	cout << obj.y << endl;

	return 0;
}
http://www.dtcms.com/a/107034.html

相关文章:

  • 智谱发布AI Agent“AutoGLM沉思”,开启AI“边想边干”新时代
  • k8s之Ingress讲解
  • 定制化自己的 RAG 框架:结合 LlamaIndex 与自定义优化
  • c加加学习之day01
  • 解锁Azure Speech “通话转录音分析”功能,驶向服务升级高速路
  • 深度解析 Hive Reduce 数量配置:优化原则与计算公式实战指南
  • TISAX认证是什么?如何获得TISAX认证?对企业发展的好处
  • 尚硅谷shell脚本学习
  • DeepSeek+SpringAI家庭AI医生
  • 高压线防外破警示灯:让隐患无处遁形!/ 恒峰智慧科技
  • mapbox基础,加载hillshade山体阴影图层
  • Docker内网部署前后端分离项目-Windows环境下
  • 代码调试:VS调试实操
  • 民安智库:物业满意度调查是了解业主需求的关键工具
  • spring boot集成reids的 RedisTemplate 序列化器详细对比(官方及非官方)
  • 谷粒微服务高级篇学习笔记整理---thymeleaf
  • Kafka、RocketMQ、Pulsar对比
  • Linux 文件系统超详解
  • Java中的LocalDate类
  • 关于登录鉴权session、cookie和token
  • KMstation商品库存监控下单
  • neo4j+django+deepseek知识图谱学习系统对接前后端分离前端vue
  • angular实现连连看
  • 蓝桥杯练习:二叉树的最大深度
  • 系统与网络安全------Windows系统安全(6)
  • niuhe插件, 在 go 中渲染网页内容
  • 基于React + Antd + Java的OFD文件上传预览实现方案(OFD文件转图片)
  • 删除和关闭 Solana 中的账户和程序
  • Linux网络相关概念和重要知识(4)(序列化和反序列化、TCP协议、会话和守护进程)
  • 基于OpenCV的指纹验证:从原理到实战的深度解析