C++ Primer Chap17
中间空过了三章:
14 类的初始化, 赋值和析构
15 重载操作符和用户定义的转换
16 类 模 板
而直接由基于对象跨越到了面向对象的17章,前面的三章其实是非常重要的,这里先不写是因为我对c++还不够熟悉,看书看到这里,心情比较急躁,想先把整体的框架建立起来,再逐步细化,所以这三章只是粗略的浏览了一下,就先匆匆的进入17章,日后这三章的内容是一定要补上的,而且,就在一个月以内。同样的,arm部分的博文,还有几个程序没有分析,也是以一个月为限,一定补齐。
闲话休提,进入正文,第一段描述是关于基于对象和面向对象区别联系的(直接粘过来的哈,其实莫不如说我的博客是摘记^_^)
面向对象的程序设计扩展了基于对象的程序设计 可以提供类型 子类型的关系 这是通
过一种被称为继承 inheritance 的机制而获得的 类不再是重新实现共享的特征 而是继承
了其父类的数据成员和成员函数 C++通过一种被称为类派生 class derivation 的机制来支
持继承 被继承的类为基类 base class 而新的类为派生类 derived class 我们把基类
和派生类实例的集合称作类继承层次结构 hierarchy
可见面向对象与基于对象的本质区别就在于继承这一特性,而多态很大程度上也依赖继承,所以嘛,怪不得他们占了面向对象三要素中的两席,封装是基于对象和面向对象都有的特性。由此联系到了C++的通用和广泛,C++支持面向过程,基于对象,面向对象,泛型编程。一门语言,支持的设计模式如此之多,可略见C++的设计思想。C和java就比C++要单纯的多,很多时候单纯是优势,当然,很多时候通用是优势。不管怎么说吧,程序员好用,开发的东西好用相统一才是评价的标准。
1 C++语言初学者的一个常见的误解是 希望基类和派生类的成员函数构成一个重载函数
集 例如
class Diffident {
public:
void mumble( int softness );
// ...
};
class Shy : public Diffident {
public:
// 隐藏了 Diffident::mumble 的可视性
// 它们没有形成一对重载实例
void mumble( string whatYaSay );
void print( int soft, string words );
// ...
};
但是 试图在派生类中调用基类实例却导致一个编译时刻错误 例如
Shy simon;
// ok: Shy::mumble( string )
simon.mumble( "pardon me" );
// 错误: 期望第一个实参是 string 类型
// Diffident::mumble( int ) 不可见
simon.mumble( 2 );
如果我们真的希望为基类和派生类的成员实例提供一个重载函数集合 该怎么办呢 我
们需要在调用基类实例的派生类中写一个小的inline 存根函数吗 显然 这样做实现了我们
的目标
class Shy : public Diffident {
public:
// ok: 方法之一: 为基类和派生类的成员
// 提供一个重载函数集合
void mumble( string whatYaSay );
void mumble( int softness ) {
Diffident::mumble( softness ); }
// ...
};
但是在标准C++中 这不是必需的 我们可以使用using 声明 using declaration 获得
同样的结果 如下所示
class Shy : public Diffident {
public:
// ok: 在标准 C++ 下 通过 using 声明
// 创建了基类和派生类成员的重载集合
void mumble( string whatYaSay );
using Diffident::mumble;
// ...
};
2 Query 基类定义了一个静态数据成员_text_file
static vector<string> *_text_file;
派生类NameQuery 会创建第二个_text_file 实例 对于NameQuery 类而言是惟一的 吗
不 所有派生类对象都引用这个相同的 单一的 共享的静态成员 不论从Query 派生了多
少类 _text_file 只存在一个实例 如果愿意的话 我们可以通过派生类对象用成员访问语法
来访问它
nameQueryObject._text_file; // ok
3 虚拟函数和缺省实参
考虑下面简单的类层次结构
#include <iostream>
class base {
public:
virtual int foo( int ival = 1024 ) {
cout < "base::foo() -- ival: " < ival < endl;
return ival;
}
// ...
};
class derived : public base {
public:
virtual int foo( int ival = 2048 ) {
cout << "derived::foo() -- ival: " << ival << endl;
return ival;
}
// ...
};
类设计者的目的是 如果不带实参而调用foo()的基类实例 则应该传递给它缺省实参
1024 例如
base b;
base *pb = &b;
// 调用 base::foo( int )
// 意图是, 应该返回 1024
pb->foo();
类似地 若程序员的目标是foo()的派生类实例 如果不带实参调用 则应该传递给缺省
实参2048 例如
derived d;
base *pb = &d;
// 调用 derived::foo( int )
// 意图是, 应该返回 2048
pb->foo();
正如所发生的 这不是C++虚拟机制的语义行为 例如 下面的小程序使用了我们的类
层次结构
int main()
{
derived *pd = new derived;
base *pb = pd;
int val = pb->foo();
cout << "main() : val through base: "
<< val << endl;
val = pd->foo();
cout << "main() : val through derived: "
<< val << endl;
}
编译并运行它 程序产生下列输出
derived::foo() -- ival: 1024
main() : val through base: 1024
derived::foo() -- ival: 2048
main() : val through derived: 2048
在这两个调用中 foo()的派生类实例被正确调用 这是因为 foo()调用的真正实例是
在运行时刻根据pd 和pb 指向的实际类型决定的 然而 传递给foo()的缺省实参不是在运行
时刻决定的 而是在编译时刻根据被调用函数的对象的类型决定的 当通过pb 调用foo()时
缺省实参中base::foo()的声明决定 为1024 当通过pd 调用foo()时 缺省实参由derived::foo()
的声明决定 为2048