揭开私有继承的面纱

Windows MCP 安装教程:让 AI 代理与 Windows 系统无缝交互 通过以上步骤,你已经成功安装和配置了 Windows MCP 服务。现在你的 Cursor 编辑器可以通过 MCP 协议与 Windows 系统进行深度交互,AI 代理能够:启动和控制应用程序执行系统命令自动化 UI 操作获取系统状态信息这为 AI 辅助开发和工作流程自动化提供了强大的基础。如果你在使用过程中遇到任何问题,欢迎在评论区讨论或查看项目的官方文档。 阅读详情
 

揭开私有继承的面纱

本文来自:http://blog.youkuaiyun.com/tonywearme/article/details/7039963

         什么是私有继承?以前在学校学习的时候,冥冥乎知道有这样一个东西,却没有仔细研究过。后来工作中用到Boost库才开始了解它。如果说保护继承大多是为了语言完整性的话,私有继承还是有一些用途的。


私有继承 vs 公有继承


公有继承继承的是接口与实现,它表示了类与类之间is-a的关系。而私有继承继承的仅仅是实现,它表示了has-a (或者 is-implemented-in-terms-of)的关系。


         在公有继承中,基类的公有成员在派生类中仍然公有,基类拥有的接口完整无缺地传给了派生类,也就是说基类对象出现的每一个地方都可以用派生类对象替换(is-a)。因此,编译器可以安全地把派生类对象的引用、指针隐式转换为基类对象的引用、指针。而在私有继承中,基类的公有和保护成员在派生类中变成了私有,从外界来看,派生类对象不再拥有基类的行为。因此,编译器不会做类似的转换。同样,对象切片(object slicing)也只有在公有继承中才会出现。

  1. class Base  
  2. {  
  3. public:  
  4.    void f() { cout << "Base::f\n"; }  
  5. };  
  6.   
  7. class Derived1: public Base  
  8. {};  
  9.   
  10. class Derived2: private Base  
  11. {};  
  12.   
  13. void method(Base &b)  
  14. {  
  15.    b.f();  
  16. }  
  17.   
  18. int main()  
  19. {  
  20.    Base b;  
  21.    // 基类对象,ok  
  22.    method(b);  
  23.    Derived1 d1;  
  24.    // 公有派生类对象,隐式转换成基类对象,也ok  
  25.    method(d1);  
  26.    Derived2 d2;  
  27.    // 私有派生类对象,无法转换成基类对象,编译出错  
  28.    method(d2);  
  29. }  

私有继承的本质


         私有继承隐藏了基类的接口,但这些被隐藏的函数在派生类的成员函数中是可以调用的。所以,你在实现派生类函数的时候可以调用基类对象函数来完成部分功能(is-implemented-in-terms-of)。下面这个例子中,企鹅类私有继承了鸟类。没有公有继承是因为企鹅并不是严格意义上的鸟,因为它们不会飞。如果我们要求所有的企鹅在走完路以后都要蹦一下,我们完全可以重用基类的Bird::walk来完成走路这个子过程。

  1. class Bird  
  2. {  
  3. public:  
  4.    void fly();  
  5.    void walk();  
  6. };  
  7.   
  8. class Penguin: private Bird  
  9. {  
  10. public:  
  11.    // walk()作为函数实现,其本身对于外界不可见  
  12.    void jumpAfterWalk() { walk(); jump(); }  
  13. private:  
  14.    void jump();  
  15. };  

私有继承 vs 组合


         实际上,私有继承只是实现 has-a 的方式之一,对象组合(composition/aggregation/containment)同样可以达到相同的目的。还是考虑企鹅的例子,鸟类对象作为了企鹅类的一个私有成员,企鹅的行走动作是通过调用该私有成员(b)的公有成员函数(walk)来完成的。企鹅和鸟对象之间是一种包含关系。

  1. class Bird  
  2. {  
  3. public:  
  4.    void fly();  
  5.    void walk();  
  6. };  
  7.   
  8. class Penguin  
  9. {  
  10. public:  
  11.    void jumpAfterWalk() { b.walk(); jump(); }  
  12. private:  
  13.    void jump();  
  14.    Bird b;  
  15. };  
同样是 has-a 的关系,它们两个各有什么优缺点呢?

组合的优点


       (一)组合相对于继承来说耦合度较小,特别是当Penguin类hold了一个Bird对象的指针而非对象时。这时候包含Penguin定义的头文件甚至都不用包含Bird.h而只用一个向前声明即可。这样的好处是,当Bird的内部实现发生变化时,Penguin类不需要重新编译。这在大型项目中非常重要。
  1. // bird.h  
  2. class Bird  
  3. {..};  
  4.   
  5. // penguin.h  
  6. class Bird;  
  7. class Penguin  
  8. {  
  9. ..  
  10. private:  
  11.    Bird *b;  
  12. };  
        (二)Penguin类可以同时有多个Bird类的对象成员b1,b2.. 继承是无法做到这点的。

私有继承的优点


         (一)你要继承一个类,但只希望保留其中的部分公用接口。首先,公有继承肯定不合适,因为基类接口必须全部保留。用组合可以实现,但是由于组合不会把子对象的接口暴露出来,你需要重新定义那些你希望保留的接口。为了实现接口,你需要调用子对象的相应函数。相比较之下,私有继承就简单很多。因为基类的接口派生类都有,只不过是私有的,重新把它们声明为公有即可。比如下面这个例子,派生类只希望暴露f1和f2这两个接口。
  1. class Base  
  2. {  
  3. public:  
  4.    void f1();  
  5.    void f2();  
  6.    void f3();  
  7. };  
  8.   
  9. // 使用私有继承,暴露部分接口的工作变得非常简单  
  10. class Derived1: private Base  
  11. {  
  12. public:  
  13.    using Base::f1;  
  14.    using Base::f2;  
  15. };  
  16.   
  17. // 使用组合,稍微复杂些  
  18. class Derived2  
  19. {  
  20. public:  
  21.    void f1() { b.f1(); }  
  22.    void f2() { b.f2(); }  
  23. private:  
  24.    Base b;  
  25. };  
      (二)如果你希望重新定义一个类的虚函数,那么只好用私有继承。这点并没有看上去那么容易理解:由于是私有继承,怎样才能实现运行时多态呢?毕竟,基类的指针指向派生类对象是不允许的。如果不能调到派生类重新定义的虚函数,我们实现它又有什么意义呢?下面这个例子给出了一种可能的模型。
  1. class Base  
  2. {  
  3. public:  
  4.    void f1() { vf(); } // 相当于this->vf(),运行时多态  
  5. protected:  
  6.    virtual void vf() { cout << "Base::vf()\n"; }  
  7. };  
  8.   
  9. class Derived: private Base  
  10. {  
  11. public:  
  12.    void f2() { f1(); }  
  13. private:  
  14.    virtual void vf() { cout << "Derived::vf()\n"; }  
  15. };  
  16.   
  17. int main()  
  18. {  
  19.    Derived d;  
  20.    d.f2(); // 打印 "Derived::vf()"  
  21. }  
      (三)如果要保证一个类不具有拷贝属性(例如mutex,数据库连接等),应该怎么做?一种方法是把拷贝构造函数、赋值运算符私有化。但还是有一个问题,类的成员函数还是可以调用它们。一个更好的办法是继承boost::noncopyable。只有当有对象拷贝动作的时候,编译器才会合成出拷贝构造函数等,这时候编译出错,因为基类的拷贝函数无法访问;当没有拷贝动作时,不会生成拷贝函数,一切正常。注意,由于noncopyable的构造析构是保护属性,组合方式不可行,只能使用继承。虽然私有和公有继承技术上都可行(因为所有noncopyable的函数都已经不是公有了),但私有继承更好,因为这里正是一个is-implemented-in-terms-of 而非 is-a 的关系。
  1. class noncopyable  
  2. {  
  3. protected:  
  4.    noncopyable() {}  
  5.    ~noncopyable() {}  
  6. private:  // emphasize the following members are private  
  7.    noncopyable( const noncopyable& );  
  8.    const noncopyable& operator=( const noncopyable& );  
  9. };  
  10.   
  11. class MyClass: private boost::noncopyable  
  12. {..}  
  13.   
  14. int main  
  15. {  
  16.    MyClass d1, d2;  
  17.    d1 = d2; // 编译出错  
  18. }  

       (四)最后,当你需要用到一个类保护成员的时候,不得不用私有继承。因为保护成员对于外界不可见,但对于派生类可见。


虚析构函数的思考

        

        当私有继承一个基类时,派生类对象不再是基类对象,编译器也不会执行隐式类型转换,因此也不会出现通过基类指针释放派生类对象的问题。所以,如果你写了一个类不打算做基类,或者只打算作为以后派生类的实现(私有继承),那么大可不必有虚析构函数。上面的 boost::noncopyable 就是一个例子。


小结:
  1. 私有继承中,基类所有的成员在派生类中都为私有。编译器也因此不会做从派生类到基类的隐式类型转换。
  2. 公有继承表示 is-a 的关系,私有继承表示has-a 或 is-implemented-in-terms-of 的关系。
  3. 私有继承和组合都表示 has-a 关系,各有千秋。一般来说,能用组合尽量用组合,因为它松耦合,维护也比较简单直观。当必须使用私有继承时才使用它。
地质工程师必备:Dips软件从数据导入到主结构面分析的完整流程解析 本文详细解析了地质工程师使用Dips软件进行主结构面分析的完整流程。从数据准备与导入、结构面分组与扇形区划分,到主结构面计算与工程解读,系统阐述了如何将野外节理数据转化为控制岩体稳定性的关键信息。重点介绍了利用等值线图识别优势组、计算统计主值及其置信椭圆,并强调了地质判断与工程应用结合的重要性。 阅读详情

相关推荐

CDR学习笔记——02

这篇写一些高级CDR的架构原理。

... 1017

C++私有继承

私有基类的私有成员按规定只能被基类的成员函数所访问,在基类外当然不能够被访问它们,因此,它们在派生类中山隐藏的,不可访问。私有基类的公有成员和保护成员在派生类中的访问属性,相当于派生类中的私有成员,即派生类的成员函数能访问它们,而在派生类外不能访问它们。私有基类的私有成员在派生类中成为不可访问的成员,只有基类的成员函数可以引用它们。提示在main()函数中,对stud.name成员变量的访问异常,是private属性,所以,不可以在类外进行访问。所以,一个成员在不同的派生层次中的访问属性可能是不同的。

LC的专栏 2854

FreeSWITCH视频通话实战:关键配置文件解析与编解码优化

本文详细解析了FreeSWITCH视频通话实战中的关键配置,重点介绍了如何通过修改`conf/vars.xml`和`sip_profiles/internal.xml`文件来启用媒体代理、优化编解码器设置(如H.264和VP8),并解决常见的视频流协商与网络穿透问题,帮助用户快速实现稳定、高质量的视频通话功能。

js777的博客 256

什么是私有继承

私有继承是 C++ 中的一种继承方式,它使得基类的公有和保护成员,在派生类中,变为派生类的私有成员。也就是说,派生类的实例对象不能直接访问基类的公有成员,但可以在派生类的定义体内部访问基类的公有成员和保护成员。“私有继承”,类似于一个私生子,私生子可以有父类的能力,但是不能让外人看到其本质,需要私生子自己包装一下,也就是,将父类的接口包含在自己的对外接口的定义体内部。这样,私生子有父类的能力,但是外人也看不到其本质。公有继承:基类的公有成员在派生类中仍然是公有的,允许外部访问,表示“是一个”关系。

LIUMINGHUA111的博客 1984

深入解析6T SRAM的读写机制与性能优化

本文深入解析了6T SRAM的基本结构与核心工作原理,详细阐述了其读写操作的具体时序与机制。文章重点探讨了在先进工艺下面临的读写稳定性、写入能力等性能挑战,并系统介绍了写入辅助与读取辅助等关键优化技术,旨在提升SRAM的可靠性与整体性能。

weixin_29205061的博客 1227

实战解析:如何用Python逆向破解FastMoss的TikTok数据加密签名(附完整代码)

本文详细解析了如何用Python逆向破解FastMoss平台的TikTok数据加密签名机制,包括MD5加密算法和JS逆向分析。通过完整的Python代码示例,帮助开发者理解签名生成原理并实现自动化请求,提升数据获取能力。

weixin_30955617的博客 559

C++学习笔记——私有继承、多重继承、类模板

例如,我们可以使用模板参数来定义成员变量和成员函数,或者使用特化(partial specialization)和偏特化(full specialization)来针对不同的情况实现不同的行为。私有继承是一种比较特殊的继承方式,它在语法上与公有继承和保护继承没有太大区别,但是其继承关系所暴露的接口和成员变量都会被隐藏起来,只有派生类自己可以访问到基类的成员。此外,多重继承也可以用来实现接口继承和实现继承的分离,从而更好地实现面向对象的编程思想。是一个类模板,可以使用不同类型的数据来实例化。

华数云图小分队的博客 1707

一文说清STM32CubeMX中文汉化全流程(图解说明)

详细讲解STM32CubeMX中文汉化的完整流程,通过图文并茂的方式手把手教学,解决界面英文带来的使用障碍,让开发更高效。掌握stm32cubemx中文汉化技巧,提升嵌入式开发体验。

weixin_42499004的博客 6278

2.2C++公有继承与私有继承

C++中的公有继承是指一个类可以从另一个类继承公有成员,包括公有成员函数和变量。

小鱼仙倌的博客 969

【docker】第10篇 Failed with result ‘exit-code和Start request repeated too quickly和Failed to start Docker

【docker】解决 Failed with result 'exit-code'和Start request repeated too quickly和Failed to start Docker。

Fanjufei的博客 6820

【转录调控网络】代谢组学与其他组学的联合分析经典模式简介

多组学联合分析经典模式转录组学&代谢组学联合分析 转录组学&代谢组学联合分析 转录组是获得生物体内基因表达的重要方法,代谢组是生物体表型的基础和直接体现者。 转录组测序可以得到大量差异表达基因和调控代谢通路,但由于基因与表型之间很难之间关联,导致关键的信号通路难以确定,因此往往达不到预期的研究目的。代谢产物是生物体在内外调控下基因转录的最终结果,是生物体表型的物质基础。 在系统生物学研究时代,生物过程复杂多变,基因调控网络复杂。针对特定的生理、病理等表型进行研究,利用转录组的数据获得大量差异

小哲的博客 6195

揭开私有继承的面纱 && 条款 42: 明智地使用私有继承

如果说保护继承大多是为了语言完整性的话,私有继承还是有一些用途的。 私有继承 vs 公有继承 公有继承继承的是接口与实现,它表示了类与类之间is-a的关系。而私有继承继承的仅仅是实现,它表示了has-a (或者 is-implemented-in-terms-of)的关系 在公有继承中,基类的公有成员在派生类中仍然公有,基类拥有的接口完整无缺地传给了派生类,也就是说基类对

lujiandong1的专栏 586

T113-S3-官方SDK分区添加

本篇文章将展示如何编译T113-S3的SDK以及在sdk中添加用户自定义分区,让您能够轻松地开始在您的项目中使用T113-S3芯片。T113-S3是一款功能强大的嵌入式处理器,适用于各种应用,包括物联网、工业自动化和智能家居等。T113-S3-SDK是特别为T113-S3芯片设计的软件开发工具包(Software Development Kit)。它包含了一系列用于开发和定制嵌入式应用程序的工具、库和示例代码,方便开发者在T113-S3平台上开展软件开发工作。

flypig has a dream! 2360

深入浅出理解面向对象:私有化、封装与继承

面向对象的私有化、封装和继承是编程中的核心概念,它们从不同层面解决了程序设计中的问题:私有化保障数据安全,封装实现模块化设计,继承提高代码复用。掌握这些概念,不仅能帮助我们写出更优质的代码,更能培养我们的面向对象思维,为后续学习更复杂的设计模式打下坚实基础。希望本文的讲解和代码示例能帮助大家真正理解这些概念,在实际开发中灵活运用,不断提升自己的编程水平。

weixin_49336861的博客 1097

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

代码的传承与升华:揭开Java继承机制的神秘面纱

在Java编程的广袤天地中,继承犹如一条神秘而灵动的纽带,串联起类与类之间的关联,编织出程序世界的层次脉络。它不仅是构建高效代码体系的重要基石,更承载着代码的传承与创新,让开发者在编程的征途上能够站在“巨人的肩膀”上,不断探索与突破。

weixin_52880903的博客 416

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Linux入门之揭开linux神秘的面纱

揭开Linux的神秘面纱 一、Linux的概况 1、 简述 Linux是一套自由加开放源代码的类Unix操作系统,是一个基于POSIX和Unix的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的Unix工具软件、应用程序和网络协议,可支持32位和64位硬件。Linux继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。 2、发展历史 1991 年,芬兰赫尔辛基大...

gulang_luofeng的博客 215

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

【C++高阶】C++继承学习手册:全面解析继承的各个方面

当我们踏上C++编程的旅程时,继承无疑是一个无法回避且至关重要的概念。作为面向对象编程的三大特性之一,继承不仅让我们能够创建出层次清晰、结构合理的代码,还极大地提高了代码的可重用性和可维护性。在本文中,我们将一起深入探讨C++继承的奥秘,从基础概念到高级应用,逐步揭开它的神秘面纱

EterNity_TiMe_的计算机学习之路 2451

从“爸爸的遗产”到“儿子的代码”:C++继承探秘

如果你曾为两个功能相似的类反复复制粘贴代码而头疼,继承就是你的解药。它不仅是代码复用的利器,更是实现多态和抽象的核心工具。在C++中,继承分为公有继承()、保护继承和私有继承三种方式,每种方式控制着父类成员在子类中的“可见性”,就像给家族遗产设置不同的权限保险箱。此外,C++还支持多重继承,允许一个子类同时继承多个父类——虽然这像同时继承“钢琴家爸爸”和“数学家妈妈”的基因一样强大,但也可能引发“菱形继承”的复杂问题。接下来的内容,我们将用代码示例和类比,带你揭开继承的神秘面纱。

KevinRay_0854的博客 1253

揭开ArrayList 的长度扩展神秘面纱

Java中的ArrayList的初始容量和容量分配 List接口的大小可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。 ArrayList继承于List接口,除继承过来的方法外,还提供一些方法来操作内部用来存储列表的数组的大小。 每个ArrayList实例都有一个容量。该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向ArrayList中不断

u013628337的专栏 673

C++继承:代码复用的魔法秘籍

在 C++ 的世界里,继承是面向对象编程的核心机制之一,它赋予了代码强大的生命力和复用性。想象一下,你正在建造一座大厦,继承就像是搭建模块化的建筑组件,通过复用已有的设计和结构,大大提高了建造的效率和质量。

大雨淅淅的博客 1000

JavaScript 中的多重继承与 ES6 中的继承

综上所述,JavaScript 中的多重继承和 ES6 中的继承为我们提供了强大的代码复用和组织能力。在 JavaScript 的奇妙世界中,继承如同一条坚韧的线索,将代码的各个部分紧密相连,构建出复杂而有序的程序结构。今天,我们将深入探索 JavaScript 中的多重继承以及 ES6 中带来的全新继承概念,一同揭开这神秘面纱背后的精彩。ES6 中的模块系统提供了一种有效的方式来管理模块的状态,使得模块可以在不同的环境中正确地初始化和运行。ES6 中的继承不仅简化了语法,还提供了更好的可读性和可维护性。

w1404273025的博客 889

五分钟透彻理解Python继承与多态

深入理解继承与多态不仅限于语法,更重要的是理解其背后的原理和设计模式。通过抽象基类加强类型约束,利用封装保护数据,都是提高代码质量的关键。好了,今天的分享就到这里了,我们下期见。如果本文对你有帮助,请吧!

wenjie20070212的博客 1602

手写实现springmvc,揭开springmvc神秘的面纱

首先来看一下springmvc的整体流程: ⑴ 用户发送请求至前端控制器DispatcherServlet ⑵ DispatcherServlet收到请求调用HandlerMapping处理器映射器。 ⑶ 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。  ⑷ DispatcherServlet通过H...

baidu_36611723的博客 398
上一篇: 数据结构算法集
下一篇: 归并排序的实现
mal327
博客等级 码龄17年 155粉丝 87原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值