第三章 类类型

1.类机制支持新类型的设计,其实,在面向对象的思想里,任何事物都是对象。包括一种类型,比如int型,也是一种对象。所以,我们应该把类和int型这样的类型辩证联系的看待。

2.本节以String类(注意,是大写的,标准库是string)为例(这个类是我们自己写的),介绍它的抽象的设计与实现。实现将着重说明C++对操作符重载(运算符重载)的支持。

3.String类需要完成的任务,或者说它需要具有的功能:

   初始化

   赋值,包括用字符串文字(string)和C风格字符串,或者是另一个String对象进行初始化或者赋值

   支持用索引访问String中的单个字符

   确定String长度(size())

   两个String对象的相等比较,或者String同C风格字符串,或者string字符串比较。

   读写一个String对象

    访问底层的C风格字符串。

接下来我们便来一步步实现这个类。


4.一般的,一个类包括共有的(public)的操作部分和私有的(private)数据部分。这些操作被称为该类的成员函数(member function)或方法(method),他们定义了类的公有接口(public interface)——即,用户可以在该类对象上执行的操作的集合。


5.我们的String类的私有数据包括:_string,一个只想动态分配的字符数组的char*类型的指针。_size,记录String中字符串长度的int型变量。

现在我们来初步写下这个类(注意,我们目前为止还没出现过String这个类,所以我们有很多操作要借助于已有的char*字符串和string字符串。

class String

{

public:

    //三个构造函数,提供了自动初始化的功能

    String();

   String(const char*);

   String(const String&);


//析构函数,自动析构

   ~String();

//一组重载的赋值操作符

    String & operator=(const String&);

    String & operator=(const char*);


//一组重载的等于操作符

bool operator==(const String&);

bool operator==(const char*);


//重载的下标操作符

char &operator[]{(int);

//成员访问函数 

int size(){return _size};

char* c_str(){return  _string};


private:

int _size;

char *_string;

}


6.接下来我们来详细解释一下这个函数的功能

首先是构造函数,第一个构造函数是缺省构造函数。他不需要做任何显式的初始值。当我们写下String str1;的时候,我们调用的解释缺省的构造函数。


第二个构造函数采用char*类型的字符来初始化。第三个构造函数被称为拷贝构造函数。因为它用另一个对象的拷贝来初始化一个对象。


被重载的操作符采用下面的一般形式:

return_type operator op(parameter_list);  即返回类型+operator关键字+被重载的符号+参数列表。


类的成语那函数可以被定义在类中,也可以定义在类的外面(但是都必须先在类之中声明)。在类定义之外定义的成员函数不但要告诉编译器它们的名字,返回类型,参数表,而且还要说明它们所属的类。一般情况下,我们应该把类成员函数的定义放到一个程序文本文件中(汝String.cpp),并且把含有该类定义的头文件(String.h)包含进来。比如我们写一下重载==的函数

#include “String.h"

#include<cstring>

//以下是==重载函数的具体代码

bool  String::operator==(const String &rhs)//其实就是在返回类型后面,函数名字前面加上了类名以及::符号。

{

   if(_size!=rhs._size)

            return false;

  return strcmp(_string,rhs._string)?false:true;

}

此处先注意?:表达式,前面是判断语句,前面为true则返回第一个选项,前面的语句为false,则返回第一个选项。

在注意strcmp()函数,他比较两个字符串(C风格)若相等,返回0(也就是false),否则返回true.所以,当这两个字符相等的时候,因为返回的是0(false),所以会使得问号表达式选择后面的选项,也就是true.反之亦然。

7、因为等于操作符是个可能要频繁调用的小函数,所以我们把它声明为内联(inline)函数是个好办法。内联函数会在每个调用点上被展开,因此,这样做可以消除函数调用相关的额外消耗。只要该函数被调用足够多次,内联函数能显著的提高性能,在类外定义的成员函数如果想声明为内联函数,必须显示的生命为inline。在类内定义的函数本来就是被缺省的定义为内联函数了。

inline bool
String::operator==(const String &rhs)
{
// 如前
}


8.在类体外定义的内联函数,应该被写在包含有该类定义的头文件中,而不是.cpp文件中。也就是说,这个函数没有写在类里面,但是写在了类定义的那个文件中(.h文件)。并且要在之前加上inline字样。


9.构造函数的名字与类名相同。但是,注意我们不能在它的声明或构造函数体重指定返回值。它的一个或多个实例都可以被声明为inline。

比如,我们把三个构造函数的代码写出来。

// 缺省构造函数
inline String::String()
{
_size = 0;
_string = 0;
}
inline String::String( const char *str )
{
if ( ! str ) {
_size = 0; _string = 0;
}
else {
_size = strlen( str );//此处注意strlen测的是char*字符串的实际有用的长度,不包含最后的结尾字符\0。所以这也是下面需要+1的原因,否则无法复制。
_string = new char[ _size + 1 ];
strcpy( _string, str );
}
}
// 拷贝构造函数
inline String::String( const String &rhs )
{
_size = rhs._size;
if ( ! rhs._string )
_string = 0;
else {
_string = new char[ _size + 1 ];
strcpy( _string, rhs._string );
}
}


9.由于我们用了new表达式动态的分配内存来保留字符串。所以当不再需要该字符串对象的时候,我们必须用delete表达式释放该内存区。这就要用到析构函数了。

inline String::~String() { delete [] _string; }//注意,此处的【】与new[]相对应。这是对于数组而言的。


10.接下来我们写出剩下的赋值操作符的重载函数

inline String&
String::operator=( const char *s )
{
if ( ! s ) {
_size = 0;
delete [] _string;
_string = 0;
}
else {
_size = strlen( s );
delete [] _string;//注意这里,在赋值之前都把现有的对象先释放掉
_string = new char[ _size + 1 ];
strcpy( _string, s );
}
return *this;//这句是关键,返回本身,也就是返回这个被赋值的String类型对象。this是个指针,指向当前操作的对象
}


//另一种赋值操作(用一个String给另一个String对象赋值)需要考虑避免着两个对象不是同一个对象,这时候this指针又起到作用

inline String&
String::operator=( const String &rhs )

{
if ( this != &rhs )

{
delete [] _string;
_size = rhs._size;
if ( ! rhs._string )
_string = 0;
else {
_string = new char[ _size + 1 ];
strcpy( _string, rhs._string );
}
}


11.接下来是下标操作符的重载

#include <cassert>
inline char&
String::operator[]( int elem )
{
assert( elem >= 0 && elem < _size );
return _string[ elem ];//因为char*类型是支持下标操作符的。
}




   

   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值