C++ Prime Plus 第10章 对象和类
1. OOP特性
- 抽象
- 封装(将实现细节放在一起并将它们与抽象分开被称为封装,种类:1)数据隐藏 ;2)将类函数定义和类声明放在不同文件中)和数据隐藏(将数据封装到私有部分从而保护数据的完整性称为数据隐藏)
- 多态
- 继承
- 代码的可重用性
2. 抽象和类
2.1 类的组成
- 类声明:数据成员描述数据部分+成员函数(方法)描述公有接口,一般放于头文件,类名首字母一般大写;
- 类方法定义:如何实现类成员函数,一般放于源文件;
2.2 成员的访问控制
- 数据成员一般放在私有部分,成员函数一般放在公有部分;默认访问控制为private;
- 类和结构的区别:1)结构的默认访问控制是public,类是private;2)结构限制为只表示纯粹的数据对象;
2.3 成员函数
- 成员函数的定义:
1)定义成员函数时,使用作用域解析运算符::来表示函数所属的类,也就是类作用域;
2)成员函数可以访问类的private部分; - 内联函数:定义位于类声明中的函数自动成为内联函数;但每个使用内联函数的文件都需要对其进行定义。
- 创建相应的对象时,每个对象都有自己的存储空间,用于存储内部变量和类成员;但同一个类的所有对象共享同一组成员函数,即每个成员函数只有一个副本,所有对象执行同一个代码块,只是这些代码块用于不同的数据。
3. 构造函数和析构函数
3.1 构造函数
- 作用:是一种特殊的类成员函数,在创建类对象时被自动调用,将值赋给数据成员。
- 声明和定义构造函数:1)无返回类型; 2)通过函数重载,可以创建多个同名但特征标不同的构造函数;3)其参数不能是数据成员,而是给数据成员赋值的变量,因此名称不能与数据成员一样。
- 使用构造函数
1)显示调用:Stock food = Stock("ABC",20,10.0);
2)隐式调用:Stock food ("ABC" ,20,10.0);
3)构造函数只能用来创建对象,而不能通过对象来调用构造函数。 - 默认构造函数
1)默认构造函数没有参数,声明中不包括值;
2)如果定义了其他构造函数,程序员必须为类提供默认构造函数;
3)定义默认构造函数的2种方法:一是给已有的构造函数的所有参数提供默认值;二是通过函数重载来定义一个没有参数的构造函数;一般情况下最好采用一方法;
3.2 析构函数
- 作用
1)用来释放对象使用的资源,并销毁对象的非静态数据成员;
2)无论何时一个对象被销毁时,都会自动调用其析构函数。 - 原型格式:~类名(); 析构函数没有参数,且每个类只有一个析构函数。
- 调用析构函数:
1)静态存储类对象:析构函数在程序结束时自动调用;
2)自动存储类对象:析构函数在程序执行完代码块时自动调用;
3)new创建的对象:使用delete释放内存时析构函数自动调用;
4)没有提供析构函数时:编译器自动调用一个默认析构函数。 - 1)初始化:
Stock stock2 = Stock("abcd",2,2.0);
2)赋值:Stock1 = Stock("ACD",10,50.0);
第一条语句是初始化,在创建指定值的对象时,可能会创建临时对象,也可能不会;
第二条语句是赋值,在赋值语句中使用构造函数总会在赋值之前创建一个临时对象。
二者相比,初始化效率更高。 - const成员函数:当成员函数(类方法)不修改调用对象时,就应该将其声明为const成员函数,这样可以保证不会修改调用对象。
4. this指针
- 目的:当类成员函数需要设计两个对象时,就需要this指针。
- this指针是指向用来调用成员函数的对象,一般而言,所有的类方法都将this指针设置为调用该类方法的对象的地址。例如:
const Stock & Stock::topval(const Stock &s) const
{
if(s.total_val > total_val)
return s;
else
return *this;
}
top = stock1.topval(stock2);//this指针指向stock1,因为是stock1调用的topval()方法
- this指针:对象的地址
1)this指针不占用大小,它不是对象的一部分,因此sizeof(this)
是没有值的;
2)this指针只在类成员函数中使用;
3)this指针只能用于非静态成员函数;
4)每个成员函数都有一个this指针;
5)调用:
一调用整个对象:*this
;
二调用成员变量:this->变量名
;
三调用成员函数:this->成员函数名()
;
5. 对象数组
- 声明:与标准类型数组一样,例如:
Stock mystuff [4]
; - 初始化对象数组:
1)使用默认构造函数创建数组元素:Stock mystuff [4];
2)花括号中的构造函数创建临时对象,
3)将临时对象的内容复制到对应的元素中。
例如:
Stock mystuff[4] = {
Stock("a",12.5,20),
Stock("b",200,2.0),
Stock("c",130,3.25),
Stock("d",60,6.5)
}
因此,要创建对象数组,那这个类必须有默认构造函数。
6. 类作用域
- 类成员名的作用域是整个类,只在该类中已知,在类外未知,因此使用类成员名时,必须根据上下文使用直接成员运算符(.)、间接成员运算符(->)或作用域解析运算符(::)。
- 作用域为类的常量
使用符号常量的作用域为类:
class B
{
private:
const int Months = 12;//invaild!!!
double costs[Months];
}
上面是错误的,因为类只有在创建对象时才分配内存,那么上面的语句是不能分配内存给costs的。
1)枚举常量:此方法不会创建类的数据成员,所有对象中都不包含枚举;由于创建的是枚举常量,而不是变量,因此可以不用枚举名。
class B
{
private:
enum {Months = 12};
double costs[Months];
}
2)静态变量static:该常量与其他静态常量存放在专门的一块内存中,而不是存储在对象中。
class B
{
private:
static int Months = 12;
double costs[Months];
}
- 作用域内的枚举
1) 如果类中有两个枚举,其中定义的枚举量可能会发生冲突,C++11提供了一种新的枚举:
enum class egg{S,M,L,J};
enum class fruit{S,M,L,J};
并用枚举名来限定枚举量:
egg a = egg::L;
fruit b = fruit::L;
2) 转化为整型
–隐式转换:常规枚举可以自动转换为int型,但类作用域中的枚举不能隐式转换为int型;
–显式转换:int(egg::S);