赞
踩
OOP特性:抽象、封装、数据隐藏、多态、继承和代码可重用性。C++中,用户定义类型指的是实现抽象接口的类设计。
1. 指定基本类型完成的工作:决定数据对象需要的内存数量、决定如何解释内存中的位、决定可使用数据对象执行的操作或方法。
类声明:以数据成员的方式描述数据部分,以成员函数(被称为方法)的方式描述公有接口。类方法定义:描述如何实现类成员函数
类规范:
通常,C++程序员将接口(类定义)放在头文件中,并将实现(类方法的代码)放在源代码文件中。使用类对象的程序都可以直接访问公有部分,但只能通过公有成员函数(或友元函数)来访问对象的私有成员。公有成员函数是程序和对象的私有成员之间的桥梁,提供了对象和程序之间的接口。防止程序直接访问数据被称为数据隐藏,将实现细节放在一起并将它们与抽象分开被称为封装。
数据隐藏是OOP主要目标之一,因此数据项通常放在私有部分,组成类接口的成员函数放在公有部分。
结构的默认访问类型是public,而类为private。
2. 实现类成员函数
两个特征:定义成员函数时,使用作用域解析运算符(::)标识函数所属的类;类方法可以访问类的private组件。
内联方法:其定义位于类声明中的函数都将自动成为内联函数,类声明通常将短小的成员函数作为内联函数。也可在类声明之外定义内联函数(类实现部分中定义函数时加inline),将内联定义放在定义类的头文件中。
在OOP中,调用成员函数被称为发送消息,因此将同样的消息发送给两个不同的对象将调用同一个方法,但该方法被用于两个不同的对象。
3. 使用类 要创建类对象,可以声明类变量,也可以使用new为类对象分配内存存储空间。
客户/服务器模型:客户是使用类的程序,类声明(包括类方法)构成了服务器。客户只能通过以公有方式定义的接口使用服务器。
类构造函数用于构造新对象,将值赋给它们的数据成员。其名称与类名相同,且没有声明类型。构造函数的参数表示的不是类成员,而是赋给类成员的值。
显式调用构造函数:Stock food = Stock(“Furry Mason”, 50, 2.5);
隐式调用:Stock food(“Furry Mason”, 50, 2.5);
构造函数被用来创建对象,而不能通过对象来调用。
默认构造函数是在未提供显式初始值时,用来创建对象。当仅当没有定义任何构造函数时,编译器才会提供默认构造函数,为类定义了构造函数后,程序员必须为它提供默认构造函数。定义默认构造函数两种方式:
Stock (const string &co = “Error”, int n = 0, double pr = 0.0);Stock( );析构函数(完成清理工作),没有参数。
原型:~Stock( ); 定义:Stock::~Stock( ){ };
析构函数调用时机:
| 创建的对象 | 析构函数调用时间点 |
|---|---|
| 静态存储类对象 | 程序结束自动被调 |
| 自动存储类对象 | 程序执行完代码块 |
通过new创建 | 使用delete时 |
| 临时对象 | 结束对该对象的使用时 |
在默认情况下,将一个对象赋给同类型的另一个对象时,C++将原对象的每个数据成员的内容复制到目标对象中相应的数据成员中。
若既可以通过初始化,也可通过赋值来设置对象的值,应采用效率更高的初始化方式。在赋值语句中使用构造函数总会导致在赋值前创建一个临时对象。
C++11提供了名为std::initialize_list的类,可将其用作函数参数或方法参数的类型,这个类可表示任意长度的列表,只要所有列表项的类型都相同或可转换为相同的类型。
const成员函数保证函数不会修改调用对象(将const放在函数括号后)。
声明:void show( ) const;
定义:void Stock::show( ) const{}
这种方式声明和定义的类函数被称为const成员函数。就像应尽可能将const引用和指针用作函数形参一样,只要类方法不修改调用对象就应将其声明为const。
指向用来调用成员函数的对象(this被作为隐藏参数传递给方法) this->
一般来说,所有的类方法都将this指针设置为调用它的对象的地址。每个成员函数(包括构造函数和析构函数)都有一个this指针,this指针指向调用对象,要引用整个调用对象,则可以使用表达式 *this, 即可以将 *this 作为调用对象的别名。
初始化对象数组的方案是,首先使用默认构造函数创建数组元素,然后花括号中的构造函数将创建临时对象,然后将临时对象的内容复制到相应的元素中。因此,要创建类对象数组,则这个类必须有默认构造函数。
可以在不同类中使用相同的类成员名。在类中定义的名称(如类数据成员名和类成员函数名)的作用域都为整个类,作用域为整个类的名称只在该类中是已知的。所以要调用公有成员函数,必须通过对象(定义成员函数时须使用域解析运算符)。
private: //这种方式声明枚举并不会创建类成员数据
enum {Months = 12};
double costs[Months];
staticprivate:
static const int Months = 12; //这将创建Months常量,其与其他静态
double costs[Months]; //变量存储在一起,而不是存储在对象中
enum class egg {Small, Medium, Large};
enum class t_shirt{Small, Medium, Large};
其作用域内枚举的底层类型为int。
*this是该对象的别名。C++允许将运算符重载扩展到用户定义的类型。要重载运算符,需使用被称为运算符函数的特殊函数形式,格式如:
operator op(argument_list) //op必须时有效的C++运算符
例如:
class Time{ int hours; int minutes; public: Time operator+(const Time & t) const …… }; Time Time::operator+(const Time & t) const { Time sum; sum.hours=hours+t.hours + … ; …… return sum; } //在测试程序中有两种表示法调用operator+( )方法: Time coding(2,40); Time fixing(5,55); total = coding.operator+(fixing); //函数表示法 total = coding + fixing; //运算符表示法
在运算符表示法中,运算符左侧的对象(coding)是调用对象,运算符右边的对象(fixing)是作为参数被传递的对象。
=’、函数调用‘()’、下标‘[]’、通过指针访问类成员‘->’运算符只能通过成员运算符进行重载。友元函数的原型在类声明中,并在原型声明前加关键字friend。
friend Time operator * (double m, const Time & t);
operator * ()虽在类中声明,但它不是成员函数,因此不能使用成员运算符来调用,但它与成员函数的访问权限相同。
不要在定义函数时使用
friend,类的友元函数不是成员函数,其访问权限与成员函数相同。
应将友元函数看作类的扩展接口的组成部分。类方法和友元函数只是表达类接口的两种不同机制。如果要为类重载运算符,并将非类的项作为其第一个操作数,则可以使用友元函数来反转操作数的顺序。
常用的友元:重载<<运算符
cout是一个ostream对象,能识别所有C++基本类型,这是因为对于每种基本类型,ostream类声明中都包含了相应的重载的operator<<()定义。ostream类将operator<<()函数实现返回一个指向ostream对象的引用。
cout<<x<<y; 等同于(cout<<x)<<y;
只有在类声明中的原型才能使用friend关键字,除非函数定义也是原型,否则不能在函数定义中使用它。
对于很多运算符来说,可选择使用成员函数或非成员函数来实现运算符重载。一般来说,非成员函数应是友元函数,这样它才能直接访问类的私有数据。非成员版本的重载运算符函数所需的形参数目与运算符使用的操作数数目相同;而成员版本所需的参数数目少一个,因为其中的一个操作数是被隐式地传递的调用对象。(this指针)
状态成员:描述对象所处的状态。如果方法通过计算得到一个新的类对象,则应考虑是否可以使用类构造函数来完成。
头文件cstdlib包含了srand( )和rand( )的原型,ctime包含了time( )的原型。time(0)返回程序执行到当前的时间,以秒级。srand( )函数允许覆盖默认的种子值,重新启动另一个随机数序列。使用语句srand(time(0))可使rand( )产生更随机的随机数(再次运行程序时结果会不一样)。C++使用头文件radom中函数提供更强大的随机数支持。
只接受一个参数的构造函数定义了从参数类型到类类型的转换。若使用关键字explicit限定了这种构造函数,则它只能用于显式转换,否则也可以用于隐式转换。
构造函数只用于从某种类型到类类型的转换;转换函数是用户定义的强制类型转换,可以像使用强制类型转换那样使用它们。
创建转换函数,转换为typeName类型:operator typeName();注意:转换函数必须是类方法(通过类对象调用),不能指定返回类型也不能有参数。
例:
class Stonewt { …… double pounds; public: …… operator int( ) const; }; Stonewt::operator int ( ) const { return int(pounds+0.5); //int转换将待转换的值四舍五入为最接近的整数, } /如114.4(+0.5)->114.9->114 int main() { …… //定义类对象c中pounds为128.8 cout<<int(c)<<endl; //输出为129 }
原则上最好使用显式转换,避免隐式转换
总之,C++为类提供了下面的类型转换
explicit可防止隐式转换,而只允许显式转换。operator typeName(),其中typeName是对象将被转换的类型。将类对象赋给typeName变量或将其强制转换为typeName类型时,该转换函数将自动被调用。Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。