`

《C++ Primer中文版》(第四版)信息汇总(四)

 
阅读更多

本章节包括:类、复制控制以及重载操作符与转换。

12、类
在C++中,用类来定义自己的抽象数据类型,通过定义类型来对应所要解决的问题中的各种概念,可以使我们更容易编写、调试和修改程序。

1、类的定义:(1)类可以没有成员,也可以定义多个成员,成员可以是数据、函数或类型别名;(2) 创建一个类类型的对象时,编译器会自动使用一个构造函数来初始化该对象,构造函数一般应使用一个构造函数初始化列表来初始化对象的数据成员;(3) 成员函数,在类内部,声明成员函数时必需的,而定义成员函数则是可选的,在类内部定义的函数默认为inline.

view plaincopy to clipboardprint?
class Sales_item{
public:
//默认构造函数需要初始化对象的数据成员
Sales_item():units_sold(0),revenue(0.0){}
double avg_price() const;//先声明成员函数
private:
...
};//分号很重要
double Sales_items::avg_price() const//在类外定义成员函数
{
...
}
class Sales_item{
public:
//默认构造函数需要初始化对象的数据成员
Sales_item():units_sold(0),revenue(0.0){}
double avg_price() const;//先声明成员函数
private:
...
};//分号很重要
double Sales_items::avg_price() const//在类外定义成员函数
{
...
}

2、数据抽象是一种依赖于接口和实现分离的编程技术。封装是一项将低层次的元素组合起来形成新的、高层次实体的技术。数据抽象和封装提供了两个重要优点:(1)避免类内部出现无意的、可能破坏对象状态的用户级错误;(2)随时间推移可以根据需求改变或缺陷报告来完善类实现,而无须改变用户级代码。

3、显式指定inline成员函数:在类内部定义的成员函数,将自动作为inline处理,同时也可以显式的将成员函数声明为inline,可以在类定义体内部指定一个成员为inline作为其声明的一部分,或者也可以在类定义体外部的函数定义上指定inline.在声明和定义处指定inline都是合法的。

view plaincopy to clipboardprint?
class Screen{
public:
char get() const{return contents[cursor];}//自动作为inline处理
inline char get(index ht,index wd) const;//类定义体内部指定一个成员为inline
index get_cursor() const;
}
inline Screen::index Screen::get_cursor() const//类定义体外部的函数定义上指定inline
{
return cursor;
}
class Screen{
public:
char get() const{return contents[cursor];}//自动作为inline处理
inline char get(index ht,index wd) const;//类定义体内部指定一个成员为inline
index get_cursor() const;
}
inline Screen::index Screen::get_cursor() const//类定义体外部的函数定义上指定inline
{
return cursor;
}

4、类的成员函数具有一个附加的隐含形参,即指向该类对象的一个指针,这个隐含形参命名为this,与调用成员函数的对象绑定在一起。成员函数不能定义this形参,而是由编译器隐含的定义。当我们需要将一个对象作为整体引用而不是引用对象的一个成员时,必须使用this指针。

view plaincopy to clipboardprint?
class Screen{
public:
Screen& move(index r,index c);
};

Screen& Screen::move(index r,index c)
{
index row=r*width;
cursor=row+c;
return *this;
}
class Screen{
public:
Screen& move(index r,index c);
};

Screen& Screen::move(index r,index c)
{
index row=r*width;
cursor=row+c;
return *this;
}

5、在普通的非const成员函数中,this的类型是一个指向类类型的const指针,可以改变this所指向的值,但是不能改变this所保存的地址,在const成员函数中,this的类型是一个指向const类类型对象的const指针。既不能改变this所指向的对象,也不能改变this所保存的地址。

6、有时我们希望类的数据成员可以修改,这可以通过将它们声明为mutable来实现。尽管do_display是const,它也可以增加access_ctr,该成员是可变成员,所以任意成员函数,包括const函数,都可以改变access_ctr的值。

view plaincopy to clipboardprint?
class Screen{
public:
private:
mutable size_t access_ctr;
};

void Screen::do_display(std::ostream& os) const
{
++access_ctr;
os<<contents;
}
class Screen{
public:
private:
mutable size_t access_ctr;
};

void Screen::do_display(std::ostream& os) const
{
++access_ctr;
os<<contents;
}

13、复制控制
每种类型,无论是内置类型还是类类型,都对该类型对象的一组操作的含义进行了定义。每种类型还定义了创建该类型的对象时会发生什么——构造函数定义了该类类型对象的初始化。类型还能控制复制、赋值或者撤销该类型的对象时会发生什么——类通过特殊的成员函数:复制构造函数、赋值操作符和析构函数来控制这些行为。

(1) 复制构造函数是一种特殊构造函数,具有单个形参,该形参是对该类类型的引用,当定义一个新对象并用一个同类型的对象对它进行初始化时,将显式使用复制构造函数。当将该类型的对象传递给函数或从函数返回该类型的对象时,将隐式使用复制构造函数。

(2) 析构函数是构造函数的互补,当对象超出作用域或动态分配的对象被删除时,将自动应用析构函数。

(3) 赋值操作符与构造函数一样,可以通过指定不同类型的右操作数而重载。

复制构造函数、赋值操作符和析构函数总称为复制控制。

1、智能指针就是将一个计算器与类指向的对象相关联。使用计数跟踪该类有多少个对象共享同一指针。使用计数为0时,删除对象。

14、重载操作符与转换
C++允许我们重定义操作符用于类类型对象时的含义,如果需要,可以像内置转换那样使用类类型转换,将一个类型的对象隐式转换到另一个类型。通过操作符重载,程序员能够针对类类型的操作数定义不同的操作符版本。

1、不能重载的操作符有如下:::、.*、.、?:。通过连接其它合法符号可以创建新的操作符,比如定义一个operator **以提供求幂运算是合法的。

2、重载操作符必须具有一个类类型操作符,用于内置类型的操作符,其含义不能改变,比如,内置的整型加好符号符不能重定义:

view plaincopy to clipboardprint?
int operator+(int,int);//Error:
int operator+(int,int);//Error:

3、重载一元操作符如果作为成员函数就没有形参,如果作为非成员函数就有一个形参。类似的作为类成员的重载函数,其形参看起来比操作数少1.一般情况,将算术和关系操作符定义为非成员函数,而将赋值操作符定义为成员函数。

view plaincopy to clipboardprint?
Sales_item& Sales_item::operator+=(const Sales_items&);
Sale_items operator+(const Sales_item&,const Sales_item&);
Sales_item& Sales_item::operator+=(const Sales_items&);
Sale_items operator+(const Sales_item&,const Sales_item&);

4、操作符定义为非成员函数时,通常必须将它们设置为所操作类的友元。

view plaincopy to clipboardprint?
class Sales_item{
friend std::istream& operator>>(std::istream&,Sales_item&);
friend std::ostream& operator<<(std::ostream&,const Sales_item&);
public:
Sales_item& operator+=(const Sales_item&);
};
class Sales_item{
friend std::istream& operator>>(std::istream&,Sales_item&);
friend std::ostream& operator<<(std::ostream&,const Sales_item&);
public:
Sales_item& operator+=(const Sales_item&);
};

5、输出操作符<<的重载:为了与IO标准库一致,操作符应接受ostream&作为第一个形参,对类类型const对象的引用作为第二个形参,并返回对ostream形参的引用。而且IO操作符必须为非成员函数。

view plaincopy to clipboardprint?
ostream& operator<<(ostream& os,const ClassType &object)
{
os<<...
return os;
}
ostream& operator<<(ostream& os,const ClassType &object)
{
os<<...
return os;
}

6、输入操作符>>的重载:与输出操作符类似,区别在于输入操作符必须处理错误和文件结束的可能性。

7、标准库定义的函数对象,标准库定义了一组算术、关系与逻辑函数对象类,同时标准库还定义了一组函数适配器,使我们能够特化或者扩展标准库所定义的以及自定义的函数对象类,这些标准库函数对象类型是在functional头文件中定义的。

view plaincopy to clipboardprint?
plus<int> intAdd;
negate<int> intNegate;
int sum=intAdd(10,20);//sum=30
sum=intAdd(10,intNegate(10));//sum=0
plus<int> intAdd;
negate<int> intNegate;
int sum=intAdd(10,20);//sum=30
sum=intAdd(10,intNegate(10));//sum=0

8、函数对象的函数适配器:

(1) 绑定器:它通过将一个操作数绑定到给定值而将二元函数对象转换为一元函数对象

(2) 求反器:它将谓词函数对象的真值求反。

view plaincopy to clipboardprint?
count_if(vec.begin(),vec.end(),bind2nd(less_equal<int>(),10));

count_if(vec.begin(),vec.end(),not1(bind2nd(less_equal<int>(),10)));
count_if(vec.begin(),vec.end(),bind2nd(less_equal<int>(),10));

count_if(vec.begin(),vec.end(),not1(bind2nd(less_equal<int>(),10)));

9、转换操作符是一种特殊的类成员函数,它定义将类类型转变为其它类型值的转换。转换操作符在类定义体内声明,在保留字operator之后跟着转换的目标类型,注意:必须是成员函数,不能指定返回类型,并且形参表必须为空

view plaincopy to clipboardprint?
class SmallInt{
public:
SmallInt(int i=0):val(i)
{
if(i<0||i>255)
throw std::out_of_range("Bad SmallInt...");
}
operator int() const{return val;}
private:
std::size_t val;
};

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/rocket5725/archive/2009/09/21/4576281.aspx

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics