Essential C++第4章 基于对象的编程风格

简介: Essential C++第4章 基于对象的编程风格

第4章 基于对象的编程风格

这一章,我们会设计并属于实现我们自己的class。

在之前的几章,我们已经指定Class的一些相关事项。

1、使用Class之前,要包含相应的头文件

2、class名称被视为一个类型,就像int,double一样。

3、class会提供一组操作函数,让我们作用于其object上。

4、class由两部分组成:一组公开的操作函数;一组私有的实现细节。

4.1 如何实现一个Class

我们从实现一个 栈(stack)开始,实现一个class。

什么是栈呢,栈是一种存放数据的结构,它允许我们在里面存放数值,并以 后进先出的顺序取出。我们以pushing 方式存入数值,以popping方式取出数值。

用户可能还需要其他操作,如查询stack空间是否已满(full),是否为空(empty),查询stack元素个数(size)。

 

Class的声明以关键字 class开始,随后接一个class名称:

class stack;

 

class的定义类似这样:

class Stack {

public:

//…public接口

private:

//…private实现部分

};

 class 定义有两部分:class声明,主体。

 主体中的public和private是访问权限,public 可被程序任何地方访问,private只能被class内部或class friend 访问。

 stack class的定义如下:

class Stack{

public:

bool push(const string&);

bool pop(string &elem);

bool peek(string &elem);

bool empty();

bool full();

int size() { return _stack.size();}

private:

vector<string> _stack;

};

所有的member function都要在Class内声明,如果在Class内定义,则会自动被视为inline函数。在Class外定义,必须用特殊的语法:

inline bool

Stack::empty()

{

return _stack.empty();

}

 

bool

Stack::pop(string &elem)

{

if(empty())

 return false;

elem = _stack.back();

_stack.pop_back();

return true;

}

Inline函数和Class定义 都放在对应的,h文件中。

非inline函数应该放在和class同名的.cpp文件中。

下面是Stack member function 的定义。

inline bool Stack::full()

{return _stack.size() == _stack.max_size();}

bool Stack::peek(string &elem)

{

if(empty())

 return false;

elem = _stack.back();

return true;

}

bool Stack::push(const string &elem)

{

if(full())

 return false;

_stack.push_back(elem);

return true;

}

4.2 构造函数和析构函数

编译器会在每次class object被定义时,调用构造函数(constructor)来进行初始化。

constructor(构造函数)的名称必须和Class名称相同。constructor没有返回值类型,可以被重载

最简单的constructor是default constructor,它不需要接受参数。

参数表为空 或者为每个参数提供默认值。

Member initialization List(成员初始化列表)

Triangular::Triangular(const Triangular &rhs)

:_length(rhs._length),_beg_pos(rhs._beg_pos),_next(rhs._beg_pos-1)

{}

Member initialization list 紧接在参数列表的最后的冒号后面,是个以逗号分隔的列表。

destructor(析构函数)

析构函数是class名称加上~前缀,没有返回值,也没有参数。用来释放对象的资源(释放内存。析构函数由系统自动调用。

Memberwise initialization(成员逐一初始化)

即当使用一个对象给另一个对象初始化时,对象中的成员会逐一复制。

有时默认的复制操作不符合我们的要求,我们要自定义copy constructor。

类似于:

Matrix:Matrix(const Martrix &rhs){

}

4,3 mutable(可变)可const(不变)

class 设计者在Member function身上标注const,告诉编译器,这个Member function 不会更改Class Object中的内容。

const修饰符写于]函数参数列表之后,凡是在Class主体以外定义者,如果他是一个const member function ,它必须在声明和定义处都指定const。

Member function 可以根据const与否而重载,因此可以设计这样的重载函数:

const BigClass& val() cosnt(return _val);

BigClass& val(){return _val};

针对const的mutable, 将某个成员标示为mutable,就可以宣称,对这个成员的修改不会破坏class object的常量性。(在const member function中可以修改这个成员)



4.4 this指针


this指针时Member function内用来指向其调用者的指针。



4.5 静态类成员


static(静态)data member用来表示唯一的,可以共享的Member。它可以在同一类的所有对象中被访问。


对Class而言,static data member只有唯一的一份实体。因此我们必须在代码文件中提供清楚的定义。


//.cpp


vector<int> Triangular::elems;


如果在class member function内部访问static data member,其访问方式和访问一般数据成员相同。


const static int data member可以在声明时指定初值。



Static Member function(静态成员函数)


static可以不用任何具体的对象调用:


如 Triangular::is_elem(7);


并且为了不和具体的对象有关,static Member function 不能访问non-static member。


static Member function的声明方式是在原函数前加关键字static。


在Class主体外进行定义时,无需再加static(此规则也适用于static data member)。



4.6 打造一个Iterator Class


我们可以像定义Member function那样定义运算符,运算符函数和普通函数很像,区别是它的名称就是operator加运算符号。


bool  operator==(const Triangular_iterator &) const;


int operatir*()const;


运算符重载的规则:


1、不能引入新的运算符


2、运算符操作数个数不可变


3、运算符优先级不变


4、运算符函数的参数列表至少有一个是class类型的。



运算符定义的方式可以向Member function一样,


也可以像non member function一样


Non member function 运算符的参数列表中,一定会比Member运算符多一个参数,也就是this指针。对于Member运算符来说,这个this指针隐式代表左操作数。



前++ 和后++


前++的参数表是空的,


后++的参数表得有一个int参数 inline Triangula_iterator Tirangular_iterator::


operator++(int)


{..


return …;


}


但使用时不需要传入这个int参数,编译器自动设置为0。


直接使用


it++;


即可。



4.7 friend 友类


class可以将其他function或class指定为friend,这样就可以让他们具备和class member function相同的访问权限,可以访问class 的private member。


只要在某个函数的原型前加上关键字friend就可以将它声明为某个class的关键字。


如果让class A 认为class B是自己的friend,则class B的所有函数都是A的friend。



4.8实现复制运算符(copy assignment operator)


只要为Class提供copy assignmemnt operator,它就会被用来取代默认的memberwise copy。



4.9 实现一个function object


function object 是一种提供有function call运算符的class。


通常我们将function object 作为参数传递给泛型算法。


function call运算符:


例:


inline bool LessThan::operator()(int value) const {return value<_val;}




4.10 重载iostream运算符


为了让我们的class支持


cout<<train<<endl;这种形式,我们需要重载iostream运算符。


ostream & operator<<(ostream &os, const Triangular &rhs)


{


os<<”(“<<rhs._beg_pos()<<”,”<<rhs.length()<<”,”;


rhs.display(rhs.length(),rhs._beg_pos(),os);


return os;


}


类似的可以重载>>运算符。




4.11 指针,指向Class Member Function


指向成员函数的指针和指向普通函数的指针很像,都需要指定返回类型和参数列表。


不过指向成员函数的指针还要指定 所属的class


如:


void (num_sequence::*pm)(int) = 0;



取得某个member function 的地址,对函数名词使用&运算符。,函数名称前要加class scope运算符限定。

pm = &num_sequence::Fibonacci;


相关文章
|
29天前
|
编译器 C++
C++之类与对象(完结撒花篇)(上)
C++之类与对象(完结撒花篇)(上)
33 0
|
23天前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
21 4
|
23天前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
20 4
|
1月前
|
存储 编译器 C++
【C++类和对象(下)】——我与C++的不解之缘(五)
【C++类和对象(下)】——我与C++的不解之缘(五)
|
1月前
|
编译器 C++
【C++类和对象(中)】—— 我与C++的不解之缘(四)
【C++类和对象(中)】—— 我与C++的不解之缘(四)
|
1月前
|
编译器 C语言 C++
C++入门3——类与对象2-2(类的6个默认成员函数)
C++入门3——类与对象2-2(类的6个默认成员函数)
23 3
|
1月前
|
C++
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
51 1
|
1月前
|
编译器 C语言 C++
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
18 1
|
1月前
|
存储 编译器 C++
C++入门3——类与对象2-1(类的6个默认成员函数)
C++入门3——类与对象2-1(类的6个默认成员函数)
26 1
|
24天前
|
存储 编译器 C语言
【C++打怪之路Lv3】-- 类和对象(上)
【C++打怪之路Lv3】-- 类和对象(上)
15 0