您现在的位置是:首页 >技术杂谈 >Effective C++读书笔记——item39(谨慎使用私有继承)网站首页技术杂谈
Effective C++读书笔记——item39(谨慎使用私有继承)
简介Effective C++读书笔记——item39(谨慎使用私有继承)
- 私有继承的行为与公有继承的对比:
- 公有继承:表示 “is - a” 关系,如
class Student : public Person,在必要时Student可隐式转型为Person。 - 私有继承:编译器通常不会将派生类对象(如
Student)转型为基类对象(如Person),且从私有基类继承的成员会成为派生类的私有成员,即使它们在基类中是保护或公有的。例如:
- 公有继承:表示 “is - a” 关系,如
class Person { /*... */ };
class Student : private Person { /*... */ };
void eat(const Person& p);
void study(const Student& s);
Person p;
Student s;
eat(p); // 正常,p是Person
eat(s); // 错误,Student不是Person
- 私有继承的含义:私有继承意味着 “is - implemented - in - terms - of”(是根据…… 实现的),纯粹是一种实现技术,仅在软件实现期间有意义,在软件设计期间无意义。例如:
class Timer {
public:
explicit Timer(int tickFrequency);
virtual void onTick() const;
/*... */
};
class Widget : private Timer {
private:
virtual void onTick() const;
/*... */
};
这里Widget私有继承Timer,是因为Widget需要利用Timer的特性,如onTick函数,而不是因为Widget和Timer有概念上的 “is - a” 关系。 3. 私有继承与复合的选择:
- 尽可能使用复合,只有在绝对必要时才用私有继承。绝对必要的情况主要是当涉及保护成员和 / 或虚函数时,以及一种与空间相关的极端情况。
- 当用复合代替私有继承时,可在派生类内声明一个从基类公有继承的私有嵌套类,并在派生类中放置该类型的对象。例如:
class Widget {
private:
class WidgetTimer : public Timer {
public:
virtual void onTick() const;
/*... */
};
WidgetTimer timer;
/*... */
};
这种设计比单纯使用私有继承更复杂,包含了公有继承和复合,还引入了新类WidgetTimer。但它有两个优点:一是可禁止派生类重定义onTick函数;二是可最小化Widget的编译依赖。 4. 私有继承的特殊情况 - 空基优化(EBO):
- 当处理没有非静态数据成员、虚函数和虚拟基类的空类时,若使用复合,空类数据成员会占用空间;若使用私有继承,可实现空基优化,使派生类对象大小不增加空类的额外空间。例如:
class Empty {};
class HoldsAnInt {
private:
int x;
Empty e;
};
// sizeof(HoldsAnInt) > sizeof(int)
class HoldsAnInt : private Empty {
private:
int x;
};
// sizeof(HoldsAnInt) == sizeof(int)
但 EBO 通常只在单继承下可行,且 “空” 类实际常包含 typedefs、enums、静态数据成员或非虚函数。
总之,私有继承意味着 “is - implemented - in - terms - of”,通常比复合低级。使用私有继承时应谨慎,需考虑所有可选方案,只有当它是表示类之间关系的最佳方法时才使用,比如在需要访问保护成员、重定义虚函数或实现空基优化等特定情况下。
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。





QT多线程的5种用法,通过使用线程解决UI主界面的耗时操作代码,防止界面卡死。...
U8W/U8W-Mini使用与常见问题解决
stm32使用HAL库配置串口中断收发数据(保姆级教程)
分享几个国内免费的ChatGPT镜像网址(亲测有效)
Allegro16.6差分等长设置及走线总结