公有继承与私有继承的区别

发布时间:2026/7/12 23:34:22

公有继承与私有继承的区别 公有继承与私有继承的区别一、核心概念对比特性公有继承public私有继承private关系描述is-a是一个has-a有一个/ 用…来实现接口继承保留基类接口隐藏基类接口类型兼容派生类可转换为基类不能转换代码复用方式白盒复用内部可见黑盒复用内部隐藏访问权限基类 public → 派生类 public基类所有成员 → 派生类 private二、公有继承is-a 关系2.1 定义与特点classEngine{public:voidStart(){cout引擎启动endl;}};classCar:publicEngine{// 公有继承Car is-a Engine// Car 拥有 Engine 的所有接口};intmain(){Car car;car.Start();// 可以直接调用基类方法return0;}2.2 类型兼容性classPerson{};classStudent:publicPerson{};// 公有继承intmain(){Student s;Person*ps;// 派生类指针可转换为基类指针Personrs;// 派生类引用可转换为基类引用return0;}三、私有继承has-a 关系3.1 定义与特点classEngine{private:intcylinderNum;public:Engine(intn4):cylinderNum(n){}voidEnStart(){cout引擎启动endl;}};// 私有继承Car has-a Engine用 Engine 来实现 CarclassCar:privateEngine{public:Car(intn4):Engine(n){}voidStart(){Engine::EnStart();// 内部可以调用基类方法}};intmain(){Car car;car.Start();// 通过 Car 的公有接口调用// car.EnStart(); // 错误外部不能直接访问基类方法return0;}3.2 私有继承的内存布局私有继承的内存布局 Car 对象 ----------------------------------------------------------- Engine 部分基类子对象 cylinderNum (4B) EnStart() 方法 --------------------------- Car 部分派生类新增 可能有其他成员 --------------------------- 特点基类部分存在但外部不可见四、公有继承 与 私有继承 与 组合4.1 三种方式对比方式关系接口可见性类型兼容耦合度公有继承is-a完全可见支持较高私有继承has-a完全隐藏不支持较低组合has-a完全隐藏不支持最低4.2 组合示例推荐替代私有继承// 使用组合替代私有继承classEngine{public:voidEnStart(){cout引擎启动endl;}};classCar{private:Engine engine;// 组合Car has-a Enginepublic:voidStart(){engine.EnStart();// 委托给成员对象}};intmain(){Car car;car.Start();// 通过 Car 接口调用// car.EnStart(); // 不能直接访问return0;}4.3 何时使用私有继承场景推荐方式原因需要访问基类的 protected 成员私有继承组合无法访问 protected 成员需要重写基类的虚函数私有继承可以重写虚函数实现定制不需要上述特性组合更简单耦合度更低// 需要重写虚函数时使用私有继承classBase{public:virtualvoidfunc(){coutBaseendl;}};classDerived:privateBase{public:voidfunc()override{coutDerivedendl;}// 重写虚函数voidcall(){func();}};五、多重继承与组合的选择5.1 不推荐的多重继承classDoor{public:voidOpen(){cout开门endl;}};classEngine{public:voidStart(){cout启动引擎endl;}};// 不推荐汽车有多个属性不应该用多重继承classCar:privateEngine,privateDoor{public:voidStart(){Engine::Start();}voidOpen(){Door::Open();}};5.2 推荐的组合方式// 推荐使用组合将多个属性作为成员classCar{private:Engine engine;// 引擎Door door;// 门Wheel wheels[4];// 车轮public:voidStart(){engine.Start();}voidOpenDoor(){door.Open();}};六、继承与静态成员6.1 场景一基类和派生类共享同一个静态成员classPerson{public:staticintnum;// 静态成员只有一份};intPerson::num0;classStudent:publicPerson{public:Student(){coutCreate Student: numendl;}~Student(){coutDestroy Student: num--endl;}};classEmployee:publicPerson{public:Employee(){coutCreate Employee: numendl;}~Employee(){coutDestroy Employee: num--endl;}};intmain(){Student s1,s2;Employee e1,e2;// 所有对象共享同一个 numcouts1.numendl;// 地址相同coute1.numendl;// 地址相同return0;}内存布局共享静态成员的内存布局 ------------------------------------------------------ 数据区.data Person::num 4 所有 Person、Student、Employee 对象共享 ------------------------------------------------------ Student 对象1 Student 对象2 Employee 对象1 Person 部分 Person 部分 Person 部分 (无 num) (无 num) (无 num)6.2 场景二基类和派生类各自有同名静态成员classPerson{public:staticintnum;// Person 的静态成员};intPerson::num0;classStudent:publicPerson{public:staticintnum;// Student 自己的静态成员隐藏了 Person::num};intStudent::num0;classEmployee:publicPerson{public:staticintnum;// Employee 自己的静态成员};intEmployee::num0;intmain(){Student s1,s2;Employee e1,e2;// 三个静态成员地址不同couts1.numendl;// Student::num 的地址coute1.numendl;// Employee::num 的地址coutPerson::numendl;// Person::num 的地址// 访问方式Student::num10;// 访问 Student 的静态成员Person::num100;// 访问 Person 的静态成员return0;}内存布局各自独立静态成员的内存布局 数据区.data -------------------------------------- Person::num 100 -------------------------------------- Student::num 10 -------------------------------------- Employee::num 0 -------------------------------------- 注意三个静态成员相互独立地址不同七、完整示例代码#includeiostreamusingnamespacestd;// 公有继承示例 classAnimal{public:voideat(){cout动物进食endl;}};classDog:publicAnimal{// 公有继承public:voidbark(){cout汪汪叫endl;}};// 私有继承示例 classEngine{private:intpower;public:Engine(intp100):power(p){}voidstart(){cout引擎启动功率powerendl;}};classCar:privateEngine{// 私有继承public:Car(intp100):Engine(p){}voiddrive(){start();// 内部可以调用基类方法cout汽车行驶endl;}};// 组合示例推荐 classComputer{private:CPU cpu;// 组合Memory mem;// 组合public:voidrun(){cpu.process();mem.load();}};// 静态成员测试 classBase{public:staticintcount;};intBase::count0;classDerived1:publicBase{public:Derived1(){count;}};classDerived2:publicBase{public:Derived2(){count;}};classDerived3:publicBase{public:staticintcount;// 隐藏基类静态成员Derived3(){count;}};intDerived3::count0;intmain(){cout 公有继承 endl;Dog dog;dog.eat();// 继承自 Animaldog.bark();// Dog 自己的方法cout\n 私有继承 endl;Carcar(150);car.drive();// car.start(); // 外部无法访问cout\n 共享静态成员 endl;Derived1 d1,d2;Derived2 d3;coutBase::count Base::countendl;// 3cout\n 独立静态成员 endl;Derived3 d4,d5;coutDerived3::count Derived3::countendl;// 2coutBase::count Base::countendl;// 3不变return0;}八、选择需求场景推荐方式原因表达is-a关系公有继承符合面向对象设计需要重写虚函数公有/私有继承私有继承也可重写只需要使用功能组合更低耦合需要访问 protected 成员继承公有或私有组合无法访问表达has-a关系组合优先更灵活更安全需要多态公有继承支持基类指针/引用九、建议优先使用组合而非私有继承除非需要访问 protected 成员或重写虚函数公有继承用于表达真实的is-a关系避免多重继承优先使用组合静态成员在继承中的行为要清楚同名会隐藏不同名则共享私有继承是实现继承不应暴露给用户

相关新闻