确定public继承塑模出is-a关系
class Person {...};
class Student: public Person {...};
void eat(const Person& p); // 任何人都会吃
void study(const Student& s); // 只有学生才到校学习
Person p; // p是人
Student s; // s是学生
eat(p); // 没问题,p是人
eat(s); // 没问题,s是学生,而学生is a人
study(s); // 没问题
study(p); // 错误,p不是学生
public 继承意味着 is-a。适用于 base class 身上的每一件事情一定也适用于 derived class 身上,因为每一个 derived class 对象也都是一个 base class 对象
避免遮掩继承而来的名称
class Base {
private:
int x;
public:
virtual void mf1() = 0;
virtual void mf1(int) { cout << "Base::mf1(int)" << endl; }
virtual void mf2() { cout << "Base::mf2" << endl; }
void mf3() { cout << "Base::mf3" << endl; }
void mf3(double) { cout << "Base::mf3(double)" << endl; }
};
class Derived: public Base {
public:
virtual void mf1() { cout << "Derived::mf1" << endl; }
void mf3() { cout << "Derived::mf3" << endl; }
void mf4() { cout << "Derived::mf4" << endl; }
};
int main(int argc, char const *argv[])
{
Derived d;
d.mf1(); // Derived::mf1
d.mf2(); // Base::mf2
d.mf3(); // Derived::mf3
d.mf4(); // Derived::mf4
// d.mf1(1); 错误,基类中的方法被覆盖
// d.mf3(3); 错误,基类中的方法被覆盖
return 0;
}
base class 中的所有名为 mf1 和 mf3 的函数被 derived class 中的名为 mf1 和 mf3 的函数覆盖。从名字搜索的观点看,Base::mf1 和 Base::mf3 不再被 Derived 继承
可以使用using
声明式
class Derived: public Base {
public:
using Base::mf1; // 让Base内的mf1和mf3的所有东西
using Base::mf3; // 在Derived作用域内可见
virtual void mf1();
void mf3();
void mf4();
};
这意味着如果你从一个带有重载函数的 base class 继承,而且你只想重定义或替换它们中的一部分,你需要为每一个你不想覆盖的名字使用 using declaration。如果你不这样做,一些你希望继承下来的名字会被覆盖
如果是 private 继承,可能会只想继承函数的某个版本,这时就不能用 using 了,可以使用转交函数
class Base {
private:
int x;
public:
virtual void mf1() { cout << "Base::mf1" << endl; }
virtual void mf1(int) { cout << "Base::mf1(int)" << endl; }
};
class Derived: private Base {
public:
virtual void mf1() { // 转交函数,forwarding function
Base::mf1();
}
};
int main(int argc, char const *argv[])
{
Derived d;
d.mf1(); // Base::mf1
// d.mf1(1); // 错误,Base::mf1(int)被遮掩了
return 0;
}
- derived classes 中的名字覆盖 base classes 中的名字,在 public 继承中,这不是我们想要的
- 为了使隐藏的名字重新可见,使用 using declarations 或者 forwarding functions