复杂的问题
,可以采用简化和抽象
的方法,将问题的本质抽象
出来,并根据特征来描述
解决方案;类是一种将抽象转换为用户定义类型的C++工具,他将数据表示和操作数据的方法组合成一个简洁的包;
类规范有两个部分组成:
接口
接口是一个共享框架,共两个系统交互时使用;
程序接口将您的意图转换为存储在计算机中的具体信息;
对类而言,指的是公共接口,公共是使用类的程序,交互系统由类对象组成,而接口由编写类的人提供的方法组成。接口让程序员能够编写与类独享交互的代码,从而让程序能够使用类对象;
然而,要使用某各类,必须了解其公共接口,要编写类,必须创建其公共接口;
class className
{
private:
data member declarations;
public:
memeber function prototypes;
};
private
和public
描述了对类成员的访问控制;使用类对象的程序都可以访问public的部分
,但只能通过public函数(或友元函数)访问对象的private部分
;公有成员函数是程序和对象的私有成员之间的桥梁,提供了对象和程序之间的接口;防止程序直接访问数据
被称为数据隐藏
;还有第三种访问控制,关键字protected,用于类继承;将实现细节放在一起并将它们与抽象分开
称为封装
;数据隐藏是一种封装,将实现的细节放在私有部分中也是一种封装,函数类定义和类声明分开放也是一种封装;通常数据项放在私有部分,组成类接口的成员函数放在公有部分,私有成员函数用于处理不属于公有接口的实现细节
;类默认的访问控制为private
;定义类成员函数时,应该使用作用域解析运算符::来标识函数所属的类
:作用域运算符确定了方法定义对应的类的身份;ClassName::FunctionName()是函数的限定名
(qualified name);而Function()是函数的全名的缩写(非限定名
qualified name);类方法可以访问类的private组件
;客户/服务器模型
客户是使用类的程序,类声明构成了服务器,它是程序可使用的资源;
客户只能通过公有方法定义的接口使用服务器,这意味着客户唯一的责任是了解该接口;
服务器的责任是确保服务器根据该接口可靠并准确的执行。服务器设计人员只能修改类设计的实现细节,而不能修改接口;
独立的对客户和服务器进行改进,对服务器的修改不会对客户的行为造成意外影响;
据点运算符.
;析构函数和构造函数是类的标准函数
;构造函数没有返回值,但也没被声明为void,构造函数实际上没有声明类型
;程序定义对象时
,将自动调用构造函数
,也可以显式调用构造函数
;构造函数的参数是要赋值给类成员的,并不能与类成员重名;无法使用对象调用构造函数;// #1
Stock fruit = Stock("apple", 100, 3);
// #2
Stock food("tomato", 300, 8);
// #3
Stock vegetable = {"tomato", 300, 8};
Stock test {"123",3,4};
Stock test2 {};
// #
默认情况下,对象赋值给另一个对象,C++将对象的每个数据成员的内容赋值到目标对象中;
默认构造函数为未提供构造函数是自动创建的
;默认构造函数没有任何参数,声明中不包含任何值,不做任何工作
;如果定义了带参数的构造函数,则定义不初始化的对象将出错(如 Stock test;),所以如果要这样应该定义一个不带参数的重载的构造函数
或者给所有参数提供默认值
,但不要同时采用两种方法;用户定义的
默认构造函数通常会给所有成员提供隐式初始化值
;
Stock first();// 错误,调用默认构造函数不能带括号,否则为定义了一个函数
Stock second("app", 123, 3);
无返回值的声明类型
,且类名前加上~
,但析构函数不能有参数,因此析构函数不能有重载;在函数后加上const关键字
;不改变类成员变量的成员函数尽量使用const限定符;// #1
const Stock food = {"test",2,3};
food.show();
this指针指向用来调用函数的对象,即值为调用它的对象的地址
,*this表示此对象本身
;必须有默认构造函数
;class Stock
{
private:
static const int one = 1;
enum {two = 2, three, four};
};
枚举名前加上class或者struct关键字
;常规枚举自动转换为整型,可赋值给整型变量或表达式,作用域内枚举不能隐式地转换为整型,但必须要是可进行显式转换;常规枚举用某种底层类型表示,长度随系统而异,二作用域内枚举底层类型为int,可显示指定类型,如#2所示,底层类型必须为整型;// #1
enum test1 {abc, def};
enum class test2 {abc, def};
int a = abc; // 正确
int b = test2::abc; // 错误
int c = int(test2::abc);// 正确
// #2
enum class : short pizza{sma, med, lar, xlar};
// #
// 基本格式
operatorop(arguement-list)
//#1
t = t1.operator+(t2); // 函数表示法
t = t1 + t2; // 运算符表示法
//#2
t = t1 + t2 + t3; // 等同于t1.operator+(t2.operator+t3)
sizeof
.
.*
::
?:
typeid
const_cast
dynamic_cast
reinterpret_cast
static_cast
=
()
[]
->
1. 友元函数 2. 友元类 3.友元成员函数
;//#1
//对象a和b使用类ABC
//运算符重载定义:ABC operator*(const double a) const;
a = b * 2.75; // 解释为 a = b.operator+(2.75)
a = 2.75 * b; // 出错
//#2
ABC operator*(const double a, const ABC &b) const;
需要在类内声明,并加上关键字friend,定义时不能使用friend关键字
;友元函数不属于类作用域,因此定义时不能用作用域运算符,即类的友元函数是非成员函数,但是它与类成员函数访问权限相同;当然也可以定义为非友元函数,如#2所示,不过定义为友元可以方便以后扩展,如添加对私有数据访问的代码;//#1
//声明
friend ABC operator*(const double a, ABC & b);
//定义
ABC operator*(const double a, ABC & b)
{
//...
}
//#1
ABC operator*(const double a, ABC & b)
{
return b*a; // 仅仅交换次序
}
//#1
abc << cout;
//#2
cout << abc;
//#3
cout << abc << def << ghi;
//
Vector Vector::operator+(const Vecotr &a) const
{
return Vector(x + b.x, y + b.y);
}
//#1
Stonewt(double lbs);
Stonewt tmp = 1.23;
//#2
Stonewt(int stn, double lbs = 0);
Stonewt tmp2 = 3;
//#3
explicit Stonewt(double lbs);
Stonewt tmp3 = Stonewt(1.23);
//#4
Stonewt tmp4 = 1000; // int to double
//#1
operator int() const; // 返回int型
//#1
Stonewt::Stonewt(double a) // 构造函数
{}
Stonewt Stonewt::operator+(const Stonewt &st) const // 成员函数
{}
Stonewt operator+(const Stonewt &st1, const Stonewt &st2) // 友元函数
{}
Stonewt a(9, 12);
double b = 3.12;
c = a + b; // 成员函数和友元函数都匹配
c = b + a; // 只有友元函数才匹配
//#2
friend Stonewt operator+(const Stonewt &st1, const Stonewt &st2)
//#3
Stonewt operator+(double x);
friend Stonewt operator+(double a, const Stonewt &st)