首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

C++ premier - 种

2012-10-29 
C++ premier -- 类自认为学过c++的我,看过《c++ premier》的第十二章“类”后,不禁感到汗颜,很多关于类的特性

C++ premier -- 类

自认为学过c++的我,看过《c++ premier》的第十二章“类”后,不禁感到汗颜,很多关于类的特性我几乎都一无所知,还常常跟java混为一谈。折腾了一天,修改了多次,才算最终把一些问题搞清楚了。呵呵,现在我还不好意思说自己搞清楚了,谁知道还有多少我不知道的呢!所以真的是要stay foolish, stay hungry啊,很多问题并不是我们以为的那么显而易见的。

?

1. 类的声明与定义

前面我们区分过变量的声明与定义。定义用于为变量分配存储空间,还可以为变量指定初始值。在一个程序中,变量有且仅有一个定义。声明用于向程序表明变量的类型和名字(所以定义也是一个声明),可以通过使用extern关键字声明变量而不定义它。

类的声明与定义跟变量的声明与定义的区别在某些程度上是相似的。类的定义给出了类包含的数据成员、成员函数,这样,一旦我们定义了类,我们就知道了所有的类成员,以及存储该类型的对象所需要的存储空间。在一个给定的源文件中,一个类只能被定义一次(就如同一个变量有且仅有一个定义)。

但是,我们也可以声明一个类而不定义它:
class Sales_item;

这个声明,有时称为向前声明(forward declaration),在程序中引入了类类型的Sales_item。在声明之后、定义之前,类Sales_item是一个不完全类型(incomplete type),即已知Sales_item是一个类型,但不知道它包含哪些成员。

?

我们可以在类定义中使用类型别名来简化类,如下示例:

#ifndef SALES_ITEM_H#define SALES_ITEM_H#include<string>class Account{public:int total();double total( class Sales_item* it );};class Sales_item{friend class unknown;friend bool compareItem( Sales_item item1, Sales_item item2 );friend double Account::total( Sales_item* y );public:typedef std::string ISBN;bool same_isbn( const Sales_item &rhs ) const{return isbn == rhs.isbn; }explicit Sales_item( ISBN book="", int sold=0, double r=0.0 ):isbn(book), units_sold(sold), revenue(r){ count++; }double avg_price( double percent );private:static int count;const static double percentOff = 0.8;ISBN isbn;unsigned units_sold;double revenue;};int Sales_item::count = 0;double Sales_item:: avg_price( double percent = percentOff ){if( units_sold )return revenue*percentOff/units_sold;elsereturn 0;}double Account::total( Sales_item* it ){return it->revenue*(Sales_item::percentOff);}#endif

?上面总共提到了三个类,Sales_item,Account以及unknown,其中unknown只有声明,没有定义。

Sales_item总共声明了三个友元,其中unknown是一个类,compareItem是一个非成员函数,因此在没有预先声明的时候就可以将它们设为友元。而Account::total则不一样,它是类Account的一个成员函数,因此在声明友元时必须先定义类Account。然而total以一个Sales_item作为输入,几乎出现了是先有鸡还是先有蛋的问题。解决的方法是对Sales_item做前向声明,这时,对于Account的定义体来说,只知道Sales_item是一种类类型,但不知道它有什么成员,因此total函数的实际定义没办法在类定义体内说明。上面的情况是我们把两个类的声明跟定义都放在一个文件里了,如果分别把两个类拆开,关系则更加复杂了。貌似没办法把Account的类定义体和函数定义放在同一个文件里。因为Sales_item的类定义体依赖于Account的类定义体,而Account的函数定义又依赖于Sales_item的的类定义体,形成了一个死循环。我找到的解决方法就是把Account的类定义体跟函数定义分开,Account的函数定义文件还需要include "Sales_item.cpp"。不知道是否还存在其他方法?

?

6. static类成员

上面这段代码同时也让我们看到了static类成员的一些特性。

首先是static数据成员必须在类定义体的外部定义,在类定义体内部只做声明。在像普通数据成员,static成员不是通过类构造函数进行初始化,而是应该在定义时进行初始化。如果没有第31行的定义,当我们定义一个类对象的时候,就会出现Undefined reference to "Sales_item::count"的错误。如果我们在类定义体内给count赋值,编译同样也会报错。例外的是,const static数据成员就可以在类的定义体中进行初始化。(书中说const static数据成员在类的定义体中初始化时,该数据成员仍必须在类的定义体之外进行定义,但是我没有在定义体外再定义percentOff,也没有出什么问题。)

由于static成员不是类对象的组成部分,static数据成员有下面一些普通数据成员不能支持的特性:

1. static数据成员的类型可以是该成员所属的类类型(非static成员被限定声明为其自身类对象的指针或引用)

2. static数据成员可以用作默认实参(如上面代码的第33行)

热点排行