继承是 C++ 里实现代码复用的基础手段。通过在原有类(基类)上扩展出新类(派生类),你可以在不重写代码的前提下增加功能。但继承机制细节不少,一不留神就会掉坑。
继承语法很简单:
class Derived : public Base {
// 新成员
};
冒号后面指定继承方式:public、protected 或 private。继承方式控制基类成员在派生类中的可见性。public 继承最常用,基类的 public 和 protected 成员保持原权限;protected 继承让它们都变成 protected;private 继承则让所有基类成员变为 private。
有个点需要明确:不论哪种继承,基类的 private 成员在派生类中都不可访问——它们仍然存在于派生类对象的内存中,但语法上阻止你使用。所以如果你想在派生类内部访问某个基类成员,又不希望外面直接碰它,用 protected。这不是 Java 里的那套,而是 C++ 专门为继承设计。另外,class 默认 private 继承,struct 默认 public 继承,但最好都显式写清楚。
实际项目中很少用 protected 或 private 继承,因为那会限制扩展性。大多数时候,你只需要 public 继承。
赋值转换与对象切片
派生类对象可以直接赋值给基类对象、指针或引用,这背后是对象切片。切片时,只把属于基类的那部分数据复制过去,派生类自己新增的成员被丢掉了。反向赋值行不通:基类对象不能直接赋值给派生类对象,这符合常理——基类对象「不知道」派生类额外都有什么。
如果你要让基类指针/引用被当作派生类指针用,必须用强制类型转换(比如 dynamic_cast),并且要确保这个指针实际指向的是一个派生类对象,否则就是未定义行为。代码大致这样:
Base* pb = &d;
Derived* pd = dynamic_cast<Derived*>(pb); // 安全,pb 确实指向 Derived
Base* p_obj = new Base(20);
Derived* pd2 = dynamic_cast<Derived*>(p_obj); // pd2 == nullptr,不安全
dynamic_cast 失败会返回空指针,不至于立即崩溃,但如果你不检查就解引用,那就悬了。
同名成员隐藏
如果基类和派生类有相同名字的成员(变量或函数),派生类的成员会隐藏基类的同名成员。这不是重载——只要名字相同,不管参数列表是否一致,基类版本统统看不见。想访问被隐藏的基类成员,只能用 Base::foo 这种作用域限定。
比如:
class Base {
public:
void fun() {}
{}
};
: Base {
:
{}
};
Derived d;
d.();
d.();


