Android C++系列:C++最佳实践4多重继承与虚继承

简介: Java和C++在语法层面比较的时候就不得不提到C++的多继承,我们知道Android是单继承,C++是多继承。在大型项目中不可避免的会用到多继承,本文分析C++多继承的一些特征。

image.png


1. 背景


Java和C++在语法层面比较的时候就不得不提到C++的多继承,我们知道Android是单继承,C++是多继承。在大型项目中不可避免的会用到多继承,本文分析C++多继承的一些特征。


2. 如何实现多继承?


C++中,我们可以在派生列表中包含多个基类:


class Sub : public Base{
  ...
}
class SubA : public Base1, public Base2{
  ...
}


关于多继承的几点说明:


  1. 每个基类均包含一个可选的访问说明符;
  2. 派生类列表只能包含已经被定义过的类;并且这些类不能是final的;
  3. C++对于派生类能继承的积累个数没有特殊规定,但是派生类列表中同一个基类只能出现一次。比如:可以Sub:public Base1,public Base2,public Base3 ....,但是不能Sub:public Base1,Base1.


3. 多继承中从每个基类中继承的状态


在多继承中,子类的对象包含每个基类的子对象,比如Sub继承Base1,Base2,Base1又继承自Base,那么Sub对象的结构如下图:


image.png


构造一个派生类的对象将同时构造并初始化它的所有基类子对象,并且多重继承的派生类的构造函数值也只能初始化它的直接子类。


子类的构造方法初始值列表将实参分别传递给每个直接父类。父类的构造顺序与派生列表中基类的出现顺序保持一致,而与派生类构造函数初始值列表中基类的顺序无关。怎么理解这句话呢?就是构造顺序与class Sub : public Base1, public Base2这个顺序有关,而与Sub::Sub(std::string name):Base1(name),Base2(){}没有关系。


在C++11新标准中,允许派生类从它的一个或几个基类中继承构造函数,但是如果从多个基类中集成了相同的构造函数,程序就会出错。


比如Base1,Base2 都有以const st::string&参数的构造函数,那么Sub同时继承Base1,Base2就会出错,这个时候我们必须专门为Sub定义自己的构造函数Sub:Sub(const std::string &s):Base1(s),Base2(s)


4. 多重继承中的类型转换


子类继承多个父类的情况下,我们可以令某个可访问基类的指针或引用直接指向一个子类对象。比如:


Base1 *base1 = new Sub();
Base2 *base2 = new Sub();
Base base = new Sub();


编译器不会在子类像基类的几种转换中进行比较和选择,因为它认为转换成哪个父类都行。但是这样会带来二义性,比如重载方法时:


void action(const Base1&);
void action(const Base2&);


当我们给action传Sub对象时就会出问题,因为编译器不知道怎么转换了。


所以我们在重载方法时要注意这种类型转换可能引起的问题。


5. 多重继承中的资源查找


在Java中我们查找属性时先从子类找,找不到再找父类,C++也是类似,但是在多重继承的结构中可能会有些复杂。


因为在查找过程中,会在所有直接基类中同时进行,如果名字在多个基类中都被找到,则这个属性的名字就产生了二义性。


我们思考一个问题,在Java中,如果我们定义了两个接口A,B,它们都有void test()这么一个方法,那么我们的Test类如果同时实现了A,B接口,具体的类该怎么实现呢?


在Java中确实比较简单,只需要实现一个test()方法就可以,但是在C++的多重继承中,父类不仅有方法还有属性,这种二义性该怎么解决呢?在C++中,对于一个派生类来说,从它的几个基类中分别继承名字相同的成员是完全合法的,只是需要在我们使用这些名字是加上前缀限定符明确指定它属于哪个基类(不调用不会出错,如果调用了还没有加前缀就会出错)。


比如上面说的test方法,我们的子类可以使用sub->Base1::text()方法来调用。


还有一种更复杂的情况,就是派生类继承的两个基类有函数名相同,但是参数列表不同的方法,这样查找是更容易出错。


**最佳实践:**为了避免二义性,除了我们在调用时加前缀,最好的办法是在派生类中为这个函数定义一个自己的版本,在函数内部来屏蔽这些二义性。比如:


int Sub::getMax() const
{
  return std::max(Base1::getMax(), Base2::getMax());
}


6. 虚继承


我们在派生类列表中见过这么一种形式:


class Base1:public virtual Base{
...
}


virtual代表虚继承,那么虚继承是做什么,要解决什么问题呢?


比如这样的一种结构:


class Base{
protected:
  int num;
}
class Base1:public Base{
}
class Base2:public Base{
}
class Sub:public Base1, Base2{
}


这种情况,Base其实被继承了两次,而默认情况派生类含有继承链上每个类对应的子部分。如果某个类在派生过程中出现多次,则派生类中将包含这个基类的多个子对象。 带来的问题呢?一句话,资源浪费。


而虚继承就是解决这个问题的,它的目的是令某个类做出声明,承诺愿意共享它的基类。我们把共享的基类子对象称为虚基类。这样,无论虚基类在继承体系出现多少次,在派生类中都只包含唯一一个共享的虚基类子对象。


**最佳实践:**在实际场景中,位于中间层次的基类将其继承声明为虚继承一般不会带来负面的问题。这样我们可以为后续使用者或者扩展着提供便捷。


7. 总结


文本介绍了C++多继承和Java实现多个接口的区别,并具体介绍了多重继承以及多重继承中的类型转换、资源查找,以及虚继承。

目录
相关文章
|
22天前
|
存储 移动开发 数据库
构建高效Android应用:探究LiveData和ViewModel的最佳实践
【4月更文挑战第20天】 在动态演化的移动开发领域,构建一个既响应迅速又能够在用户界面保持稳定的Android应用是至关重要的。近年来,随着Android架构组件的推出,特别是LiveData和ViewModel的引入,开发者得以更有效地管理应用状态并优化用户界面的响应性。本文将深入探讨LiveData和ViewModel的实现机制,并通过案例分析展示如何结合它们来构建一个高效且健壮的Android应用架构。我们将重点讨论如何通过这些组件简化数据绑定过程、提高代码的可维护性和测试性,同时确保用户界面的流畅性。
|
存储 安全 算法
【C++智能指针 相关应用】深入探索C++智能指针:跨进程、动态库与最佳实践
【C++智能指针 相关应用】深入探索C++智能指针:跨进程、动态库与最佳实践
74 5
|
2月前
|
消息中间件 负载均衡 监控
【ZMQ PUB模式指南】深入探究ZeroMQ的PUB-SUB模式:C++编程实践、底层原理与最佳实践
【ZMQ PUB模式指南】深入探究ZeroMQ的PUB-SUB模式:C++编程实践、底层原理与最佳实践
258 1
|
14天前
|
NoSQL API Redis
最佳实践|如何使用c++开发redis module
本文将试着总结Tair用c++开发redis module中遇到的一些问题并沉淀为最佳实践,希望对redis module的使用者和开发者带来一些帮助(部分最佳实践也适用于c和其他语言)。
76205 0
|
16天前
|
设计模式 编译器 数据安全/隐私保护
C++ 多级继承与多重继承:代码组织与灵活性的平衡
C++的多级和多重继承允许类从多个基类继承,促进代码重用和组织。优点包括代码效率和灵活性,但复杂性、菱形继承问题(导致命名冲突和歧义)以及对基类修改的脆弱性是潜在缺点。建议使用接口继承或组合来避免菱形继承。访问控制规则遵循公有、私有和受保护继承的原则。在使用这些继承形式时,需谨慎权衡优缺点。
24 1
|
17天前
|
安全 vr&ar C++
C++:编程语言的演变、应用与最佳实践
C++:编程语言的演变、应用与最佳实践
|
23天前
|
数据库 Android开发 开发者
实现高效安卓应用:探究LiveData和ViewModel的最佳实践
【4月更文挑战第19天】 在构建响应式的Android应用程序时,LiveData和ViewModel是两个核心组件。它们不仅提供了数据持有和界面更新的机制,还促进了组件间的解耦。本文将深入探讨如何通过结合LiveData和ViewModel来优化应用架构,提升用户体验,并确保数据的一致性和生存期管理。我们将透过实际案例分析,揭示这些技术如何协同工作以应对复杂的UI场景,并展示如何在实际项目中实施这些最佳实践。
|
28天前
|
安全 Android开发 数据安全/隐私保护
Android中的动态权限请求与最佳实践
【4月更文挑战第14天】 在现代安卓应用开发中,用户隐私和安全被赋予了前所未有的重要性。随着Android 6.0(API级别23)引入的运行时权限模型,开发者必须更加细致地处理权限请求,以确保应用功能的完整性同时不侵犯用户的隐私。本文将深入探讨如何在Android应用中实现动态权限请求,分析常见问题,并提供一系列最佳实践,以帮助开发者优雅地处理这一挑战。
32 5
|
2月前
|
移动开发 调度 Android开发
构建高效Android应用:探究Kotlin协程的最佳实践
在移动开发领域,性能优化和资源管理是至关重要的。特别是对于Android开发者来说,合理利用Kotlin协程可以大幅提升应用的响应性和用户体验。本文将深入探讨Kotlin协程的核心概念、优势以及它们在Android项目中的实际应用。我们还将通过代码示例来揭示如何有效地使用协程进行后台任务处理,避免阻塞UI线程,并确保内存的有效管理。文章的目标是为读者提供一套实用的指南,帮助他们在Android开发中充分利用Kotlin协程的强大功能。
17 1
|
2月前
|
程序员 开发工具 git
【程序员英语 代码提交】C++工程师的代码提交艺术:git commit 时 精确表达与最佳实践
【程序员英语 代码提交】C++工程师的代码提交艺术:git commit 时 精确表达与最佳实践
120 1