侯捷CPP---面向对象(上)
前言
头文件防卫式声明
避免头文件被重复包含的两种方式:
- #ifndef方式
#ifndef __COMPLEX__
#define __COMPLEX__
...//代码段
#endif
#ifndef的方式受C/C++语言标准支持。它不仅可以保证同一个文件不会被包含多次,也能保证内容完全相同的两个文件(或者代码片段)不会被不小心同时包含。
当然,缺点就是如果不同头文件中的宏名不小心“撞车”,可能就会导致你看到头文件明明存在,但编译器却硬说找不到声明的状况——这种情况有时非常让人郁闷。
由于编译器每次都需要打开头文件才能判定是否有重复定义,因此在编译大型项目时,ifndef会使得编译时间相对较长,因此一些编译器逐渐开始支持#pragma once的方式。
- #pragmaonce方式
#pragma once
...//代码段
#pragma once 一般由编译器提供保证:同一个文件不会被包含多次。注意这里所说的“同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件。
你无法对一个头文件中的一段代码作pragma once声明,而只能针对文件。
其好处是,你不必再担心宏名冲突了,当然也就不会出现宏名冲突引发的奇怪问题。大型项目的编译速度也因此提高了一些。
对应的缺点就是如果某个头文件有多份拷贝,本方法不能保证他们不被重复包含。当然,相比宏名冲突引发的“找不到声明”的问题,这种重复包含很容易被发现并修正。
另外,这种方式不支持跨平台!(有些编译器可能不支持)
class 分类
Object Based(基于对象):对单一class的设计
Object Oriented(面向对象):对多个关联class的设计
class可分为class with pointer members(complex 类)与class without pointer members(string 类)
不带指针的class(complex)
成员变量私有化
成员变量私有化的好处:保证数据的安全性,如在设置年龄时应该使用setage函数,使年龄的范围在0-200之间才合理。
inline function(内联函数)
1.若函数在class内部定义完成则自动成为inline func的候选人
2.class外定义的函数可以加上inline关键字使之成为inline func的候选人
3.由编译器决定函数到底是不是inline func,简单函数应尽量使之成为inline func,这样效率更高
构造函数
- 给构造函数赋初值的方式有两种
第一种方式:初始化列表(初始列,初值列)
class complex
{
public:
//构造函数
complex (double r = 0, double i = 0): re (r), im (i) { }
private:
double re, im;
}
第二种方式:在构造函数内部赋初值
class complex
{
public:
//构造函数
complex (double r = 0, double i = 0)
{ re=r;im=i; }
private:
double re, im;
}
- 构造函数可重载
- 构造函数可私有化
常量成员函数
- 不会改变成员变量的成员函数应加上const关键字使成为常量成员函数
参数传递
- 函数参数传递应尽量使用引用传递
- 如果不希望函数更改参数应加const关键字修饰
返回值传递
- 返回值传递尽量使用引用传递
- 决不能返回局部变量的引用,其他情况都可以返回引用
友元函数
- 友元函数可以取得private成员
- 相同class的各个objects互为友元(class内部的object互为友元)
操作符重载
操作符重载有两种定义方式
- 作为成员函数在class 内定义
- 作为全局函数在class外定义
特别地操作符<<只能作为全局函数
临时对象
通过类名(参数a,参数b)的方式可以创建临时对象,临时对象的寿命只有一行
带指针的class(string)
对于带指针的class一定要自己写拷贝构造函数、拷贝赋值、析构函数
string类的设计:
构造与析构
new关键字动态分配内存
拷贝构造与拷贝赋值
浅拷贝只拷贝指针,会造成内存泄漏等问题
带指针的class不能使用默认的拷贝构造及拷贝赋值
string的拷贝构造:
- 拷贝赋值是需要先进行自我赋值检测
- 1.删除自身(目的端)数据
- 2.将来源端数据拷贝到目的端
string的拷贝赋值:
几种object的生命周期
- stack(栈) object在作用域结束后释放
- static local objects在程序结束后释放
- global objects在程序结束后释放
- heap(栈) objects需要手动释放,否则离开作用域后指针所指的heap objects仍然存在,直到程序结束,造成内存泄漏
- array new要搭配array delete使用
补充
static
静态成员变量:所有object共享一份数据
静态成员变量一定要在class外定义(初始化)
静态成员函数:没有this指针,只能处理静态成员变量
调用静态成员的方式有两种,(1)由object调用;(2)由class name直接调用
例如:银行账户所有object应该共享一份利率
构造函数私有化(一种设计模式)
class template(类模板)
function template(函数模板)
Object Oriented(面向对象)
Composition(复合)
- 复合表示has a(有一个或多个)
- 下面是一种设计模式Adapter:已经有一个功能强大的deque,queue只开放deque的几个接口
Delegation(委托)
- 委托表示Composition by reference
- 下面是一种设计模式Handle/Body(pImpl):(右边的String只提供接口,所有的功能在左边的StringRep中实现)(有什么好处?)
Inheritance(继承)
- 继承表示is a(是一种)
- 基类的析构函数必须是虚函数(?不确定对不对)
-虚函数
后面还有一小节将的设计模式暂时用不到,没写