
OOP 学习笔记(2)——封装与接口
封装与接口
函数重载
同一名称的函数,有两个以上不同的函数实现,被称为函数重载。
比如:
编译器将根据函数调用语句的实际参数决定调用哪个函数。
多个同名函数之间必须保证可以通过参数列表区分,返回值、参数名称不能作为区分标识。
函数参数的缺省值
也就是讲过的函数参数初始值。
同样保证需要可区分。
基础知识
auto
由编译器根据上下文自动确定变量的类型,如:
追踪返回类型的函数
可以将函数返回类型的声明信息放到函数参数列表的后面进行声明。如:
- 普通函数声明形式:
- 追踪返回类型的函数声明形式:
追踪返回类型在原本函数返回值的位置使用 auto
关键字。
decltype
decltype
可以对变量或表达式结果的类型进行推导。- 重用匿名类型。
- 泛型编程中结合
auto
,用于追踪函数的返回值类型。
结合 auto
和 decltype
- 可以推导返回类型:
- C++14 中不再需要显式指定返回类型:
内存的动态申请和释放
也就是 new
/delete
运算符。
直接举例就是:
跟前面的 malloc()
和 free
很像,不做更多说明。
NULL
、0、nullptr
在 C++ 中,NULL
被定义为 0。
在 C++11 之前,可以使用 NULL
或者 0 表示空指针。
然而这样会产生一些问题:
我们可能会忽略 NULL
同时是一个 int
型常量的事实。
而 nullptr
表示严格意义上的空指针。
此时上面程序就不会报错。
基于范围的 for
循环
形式为:
其中 key
是用于迭代的变量,range
表示被迭代的范围。
如:
用户定义类型——类 class
class
——用户自定义的类型
- 包含函数、数据的加强版“结构体”(C 语言中的)。
- 其中包含函数和数据称为成员函数和成员变量。
成员函数必须在类内声明,但定义可以在类内或者类外。
- 利用这点,往往会在头文件中声明类,并在实现文件中定义成员函数。
- 一般将不同的类保存为不同的头文件和实现文件。
- 当然实际上也可以在类内直接定义成员函数,但复杂成员函数一般还是声明、定义分离的 。
类成员的访问权限
类的成员变量和函数可以根据需要设置不同的访问权限:
public
:可以在类外用.
操作符访问。private
:- 默认权限;(没有注明访问权限情况下)
- 不允许在类外用
.
操作符访问。
protected
:暂时不介绍。
具体实例可以自行尝试。
this
指针
所有成员函数的参数中,隐含一个指向当前对象的指针变量,名称为 this
。
如上面的 fill()
函数中,就可以将 data
改为 this->data
而不改变效果。
类的运算符重载
用户自定义类,没有对重用运算符进行定义,比如对于两个类对象,难以使用 a+b
。
所以,C++ 支持了对以下运算符的重载:
+
、-
、*
、/
、[]
、()
、<<
、>>
、++
、--
对于加减乘除我们就以 +
代替,其定义一般为:
比如上面的 Matrix
类可以定义矩阵加法:
对象输入输出——流运算符重载
用户自定义的类,虽然可以像内置类型那样定义变量(对象),但想要使用流运算符输入、输出对象,则还需要为其定义流运算符重载。
比如想要实现这样的功能:
流运算符重载函数的声明:
一种可能的实现为:
函数运算符 ()
重载
这种重载让对象看上去像是一个函数名:
使用方法:
此时 Obj
对象看上去就像是一个函数,故也称为函数对象,似乎也被称为伪函数。
数组下标运算符 []
重载
与前面的基本相同,但是注意只能传入一个参数。
当然这个参数的类型倒是基本没有限制,也就是可以以此构造广义的数组。
注意,如果返回值是引用,则可以作为左值,否则不行。
一个实例:
输出结果:
Monday Temperature: -3
前缀与后缀的 ++
、--
前缀运算符重载声明:
ClassName operator++();
ClassName operator--();
后缀运算符重载声明:
ClassName operator++(int dummy);
ClassName operator--(int dummy);
通过在函数体中没有使用的哑元参数 dummy
来区分前缀与后缀的同名重载。
一般哑元只定义但没有名称,比如:
友元
在类内进行友元的声明。
被声明为友元的函数或类,具有对出现友元声明的类的 private
和 protected
成员的访问权限,也就是可以访问该类的一切成员。
友元修饰的函数或类,不受 private
的影响。
上面的流运算符重载就是需要访问私有成员 data
数组才会加上友元声明。
也可以声明别的类的成员函数,为当前类的友元(包括构造函数、析构函数,后面内容):
同时也可对 class
、struct
、union
进行友元声明。
对其他类型的友元声明只会被忽略。
而一个函数也可以是多个类的友元函数。
其他注意事项还有:
- 友元不传递。
- 友元不继承。
- 友元声明不能用于定义新的
class
。
内联函数
用途
使用内联函数,编译器自动产生等价的表达式。
等价于:
和宏定义的区别
首先,宏定义是直接拷贝,可能与函数调用有不同的结果,容易出错,很多缺陷不可避免。
其次,内联函数在 Debug 版本中,没有真正内联,仍然可以调试,在 Release 版本,才实现了真正的内联。
最后,宏定义的函数无法操作私有数据成员。
注意事项
- 避免对大段代码使用内联修饰符。
- 避免对包含复杂结构的函数使用内联定义。
- 内联修饰用于函数定义而不是函数声明。
- 定义在类声明中的函数默认为内联函数。
- 一般构造函数、析构函数都被定义为内联函数。
- 在头文件加入或修改
inline
函数时,调用此头文件的源文件均需要重新编译。 - 内联修饰符更像是建议而非命令,实际上编译器往往会有判断性、智能地选择是否内联。
No Comments