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实现多个接口的区别,并具体介绍了多重继承以及多重继承中的类型转换、资源查找,以及虚继承。

目录
相关文章
|
1月前
|
移动开发 监控 Android开发
Android & iOS 使用 ARMS 用户体验监控(RUM)的最佳实践
本文主要介绍了 ARMS 用户体验监控的基本功能特性,并介绍了在几种常见场景下的最佳实践。
|
5月前
|
XML API 网络安全
【安卓】在安卓中使用HTTP协议的最佳实践
【安卓】在安卓中使用HTTP协议的最佳实践
114 4
|
6月前
|
C++
C++程序中的多重继承
C++程序中的多重继承
67 1
|
2月前
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
在Android应用开发中,追求卓越性能是不变的主题。本文介绍如何利用Android NDK(Native Development Kit)结合Java与C++进行混合编程,提升应用性能。从环境搭建到JNI接口设计,再到实战示例,全面展示NDK的优势与应用技巧,助你打造高性能应用。通过具体案例,如计算斐波那契数列,详细讲解Java与C++的协作流程,帮助开发者掌握NDK开发精髓,实现高效计算与硬件交互。
129 1
|
6月前
|
NoSQL API Redis
最佳实践|如何使用c++开发redis module
本文将试着总结Tair用c++开发redis module中遇到的一些问题并沉淀为最佳实践,希望对redis module的使用者和开发者带来一些帮助(部分最佳实践也适用于c和其他语言)。
76639 0
|
4月前
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
【7月更文挑战第28天】在 Android 开发中, NDK 让 Java 与 C++ 混合编程成为可能, 从而提升应用性能。**为何选 NDK?** C++ 在执行效率与内存管理上优于 Java, 特别适合高性能需求场景。**环境搭建** 需 Android Studio 和 NDK, 工具如 CMake。**JNI** 构建 Java-C++ 交互, 通过声明 `native` 方法并在 C++ 中实现。**实战** 示例: 使用 C++ 计算斐波那契数列以提高效率。**总结** 混合编程增强性能, 但增加复杂性, 使用前需谨慎评估。
140 4
|
3月前
|
JSON Android开发 C++
Android c++ core guideline checker 应用
Android c++ core guideline checker 应用
|
4月前
|
Java 编译器 程序员
C++中的语法知识虚继承和虚基类
**C++中的多继承可能导致命名冲突和数据冗余,尤其在菱形继承中。为解决这一问题,C++引入了虚继承(virtual inheritance),确保派生类只保留虚基类的一份实例,消除二义性。虚继承通过`virtual`关键字指定,允许明确访问特定路径上的成员,如`B::m_a`或`C::m_a`。这样,即使基类在继承链中多次出现,也只有一份成员副本,简化了内存布局并避免冲突。虚继承应在需要时提前在继承声明中指定,影响到从虚基类派生的所有后代类。**
|
3月前
|
JSON Android开发 数据格式
Android c++ core guideline checker 应用问题之JSON compilation database的定义如何解决
Android c++ core guideline checker 应用问题之JSON compilation database的定义如何解决
|
3月前
|
IDE 开发工具 Android开发
Android c++ core guideline checker 应用问题之clang-tidy 检查后发现的问题如何解决
Android c++ core guideline checker 应用问题之clang-tidy 检查后发现的问题如何解决