摘要:
从面相对象 C++ 转移到模板 C++ 时,你会发现类继承在某些场合不在好使了。 比如父类模板中的名称对子类模板不是直接可见的,需要通过 this 前缀、using 或显式地特化模板父类来访问父类中的名称。 因为父类模板在实例化之前其中的名称是否存在确实是不确定的,而 C++ 偏向于早期发现问题(e 阅读全文
摘要:
模板参数声明 上面 class 和 typename 的使用没有区别,然而 typename 和 class 对编译器而言却是不同的东西。 typename 可以用来帮编译器识别嵌套从属类型名称,基类列表和成员初始化列表除外。 声明一个类型 typename 的第一个作用在于声明一个类型。为什么类型 阅读全文
摘要:
面向对象设计中的类考虑的是显式接口和运行时多态, 而模板编程中的模板考虑的是隐式接口和编译期多态。 对类而言,显式接口是由函数签名表征的,运行时多态由虚函数实现; 对模板而言,隐式接口是由表达式的合法性表征的,编译期多态由模板初始化和函数重载的解析实现。 显式接口和运行时多态 一个类的显式接口是由 阅读全文
摘要:
多继承 多继承是 C++ 特有的概念,在是否应使用多继承的问题上始终争论不断。一派认为单继承是好的,所以多继承更好; 另一派认为多继承带来的麻烦更多,应该避免多继承。 多继承比单继承复杂,引入了歧义的问题,以及虚继承的必要性; 虚继承在大小、速度、初始化/赋值的复杂性上有不小的代价,当虚基类中没有数 阅读全文
摘要:
private 继承 public 继承表示 "is a" 的关系,这是因为编译器会在需要的时候将子类对象隐式转换为父类对象。 然而 private 继承则不然: Person 可以 eat,但 Student 却不能 eat。这是 private 继承和 public 继承的不同之处: 编译器不会 阅读全文
摘要:
一个类型包含另一个类型的对象时,我们这两个类型之间是组合关系。组合是比继承更加灵活的软件复用方法。对象组合也同样拥有它的语义: 就对象关系来讲,组合意味着一个对象拥有另一个对象,是 "has a" 的关系; 就实现方式来讲,组合意味着一个对象是通过另一个对象来实现的,是 "is implemente 阅读全文
摘要:
静态绑定与动态绑定 静态绑定是在编译期决定的,又称早绑定;动态绑定是在运行时决定的,又称晚绑定。 举例来讲,Rect 和 Circle 都继承自 Shape,Shape 中有虚方法draw。那么: 在编译期是不知道应该调用哪个 draw 的,因为编译期看到的类型都是一样的: 。 在运行时可以通过虚函 阅读全文
摘要:
不要重写继承来的非虚函数 Derived 继承自 Base。如果 Base有一个非虚函数 func,那么客户会倾向认为下面两种调用结果是一样的: 然而重写非虚函数 func 将会造成上述调用结果不一致: 因为 pb 类型是 ,pd 类型是 ,对于普通函数 func 的调用是静态绑定的(在编译期便决定 阅读全文
摘要:
替代虚函数实现的几种方案 比如你在开发一个游戏,每个角色都有一个 healthValue() 方法。很显然你应该把它声明为虚函数,可以提供默认的实现,让子类去自定义它。 这个设计方式太显然了你都不会考虑其他的设计方法。但有时确实存在更好的,本节便来举几个替代的所涉及方法。 非虚接口范式(NVI id 阅读全文