boolan / C++ 面向对象高级编程 - part1
2017-10-19 12:12:37 / helingchao
ITEM 1. C++编程简介
0. 概述
- 面向对象观念 vs 面向对象语言
面向对象是种观念, 用面向对象的观念写程序,需要支持面向对象编程的语言。
1. C++演化
版本演化
- C++ 98 (1.0) // 广泛采用
- C++ 03(TR1)
- C++ 11(2.0)
- C++ 14
2. C++ = 语言部分 + 标准库部分
ITEM 2. 头文件与类的声明
1. C vs C++, 关于数据和函数
- c语言的问题
多个函数会处理函数间共享的“全局数据”,C++通过数据封装使数据在函数间隔离。
2. Object based (基于对象) vs. object oriented (面向对象)
object based: 面对的是单一的class的设计。
object oriented :面对的是多重classes的设计,class 与class 之间的关系。
3. classes的两个经典分类:
- class without pointer members
- class with pointer members
4. 第一个程序
C++代码基本形式
1508404981111.png- 文件的扩展名形式不是固定的。
C/C++标准输出的差异
头文件中的防御式声明
头文件的布局
1508403773878.png注意前置声明 forward declaration
class的声明
1508403833855.pngcomplex类设计中体现了如下在设计class without pointer类应该注意的点:
- 成员变量都要声明为private;
- 用初始化列表在构造函数中初始化成员变量;
- 如果成员方法内不改变成员变量内容,则将该方法声明为const类型;
- 参数传递尽量采用引用;
- 如果有返回值,函数因尽量返回类型的引用:如果被返回变量是局部/临时变量则不要返回引用;
- 有两种方式重载操作符:类成员函数,非类成员函数。将操作符作为类成员函数,则操作符的左操作数必须是该类型。
- 短小的类成员函数,尽量声明为内联函数。
存取成员变量的接口设计
直接以成员变量的名称设计一对存取函数。
class Type {
public:
int& mem_name() { //成员变量读接口
return mem_name_;
};
void mem_name(int value) { // 成员变量写接口
mem_name_ = value;
}
private:
int mem_name_;
}
class template
ITEM 3. 构造函数
1. inline(内联)函数
1508403873124.png你指定的Inline对编译器来说只是建议性质的,最终是否会生效取决于编译器。
- Inline 类方法的形式:
A. 在class body内定义。
B. 在class body外显示声明。
2. access level
⚠️advise:
数据一定要放在private中。
3. 构造函数
注意带默认参数的构造函数,为用户提供多种创建对象的形式。
构造函数不需要返回值,其目的就是创建对象。
初始化列表仅能在构造函数中使用。
初始化 vs. 赋值
一个变量数值的设定有两个阶段:1. 初始化 2. 赋值
在构造函数的初始化列表中初始化成员的效率高于在构造函数体中赋值成员。
析构函数
不带指针成员的class 多半情况下不需要定义析构函数。
构造函数的重载(overloading)
1508403966008.png- 函数重载取决于:函数名称+参数类型和个数,与返回值类型无关。
- 函数重载常常发生在构造函数中。
- 避免因为参数默认值引入的多个重载函数解析时的歧义。
private的构造函数 /singleton
- 拥有private构造函数的类型,不允许类外的用户创建该类型的对象。
- singleton是一种典型的private构造函数的应用。
ITEM 4. 参数传递和返回值
1. const 成员函数
1508404019778.png⚠️ advise:
为每一个只读成员数据的成员函数加上const修饰。
设计接口时要考虑const问题。
const成员函数的目的是使该接口能被const对象访问,只读并不破坏对象的const属性,const只是限制对象的写入。
2. pass by value vs. pass by reference(to const)
- 传参数要把数据本身压入栈。
- c为避免传递参数可以使用传递指针优化,c++采用传递引用。
- 传引用底层本质是传递指针。
⚠️advise:
参数传递尽量采用引用
3. return by value vs. return by reference (to const)
return 方式也会影响效率。
⚠️advise:
尽量使用return by reference。
不能使用 return by reference 的场景:
函数执行的结果有两种存放的位置:
- 函数中创建的临时变量;
- 函数外部已经创建的变量。
函数返回值不能返回函数中创建的临时变量的引用。根据该条原则决定是否采用return by reference。
4. friend(友元)
1508404061260.png友元函数可以访问类private成员。声明我的友元要在我的类中声明。
相同class的各个objects(对象 )互为friends
1508404111977.pngITEM 5. 操作符重载与临时对象
C++允许用户定义的类重载操作符。
1. 操作符重载 -1 this (成员函数)
2297BE1E-3C24-49D2-8F5C-CE0DE256661C.png将操作符作为类成员函数重载,限制重载的操作符的左操作数必须是该类的类型。
this指针
2. return by reference 语法分析
2345EC9C-8DC3-439F-AA37-050813B98551.png为支持操作符的连接操作,操作符重载需返回类型的引用。
返回值无需是const& , 因为给表达式/语句赋值是没有意义的。
3. class body 之外的各种定义
- 全局的函数定义
- 类成员函数定义
4. 操作符重载 -2 (非成员函数)
对于以非成员函数的形式重载操作符,操作符的左右操作数类型比较灵活。不受限于在自定义的类中重载操作符,可以为已有的类型重载操作符。
5. 函数返回值不能是临时对象的引用
临时对象:typename();
临时对象的生命周期仅限于该对象创建的所在行。
int(4); // 临时对象,生命周期仅限本行。
int(); // 临时对象,生命周期仅限本行。
int a(4);
5. 重载标准输出
重载标准输出操作符时,作为入参的ostream类型不能是const &, 因为输出需要改变ostream对象的状态。
总结
如何设计class without pointer:
- 成员变量都要设计为private;
- 用初始化列表在构造函数中初始化数据成员;
- 如果成员方法内不改变成员变量内容,则将该方法声明为const类型;
- 参数传递尽量采用引用;
- 如果有返回值,函数因尽量返回类型的引用:如果被返回变量是局部/临时变量则不要返回引用;
- 有两种方式重载操作符:类成员函数,非类成员函数。将操作符作为类成员函数,则操作符的左操作数必须是该类型。
- 短小的类成员函数,尽量声明为内联函数。