C++_类

  一般来说,类的数据成员不能在类体声明时初始化,强烈推荐在构造函数中初始化这些数据成员(因为对于基本类型的数据成员而言,没有默认的初始化方法)。

  对象大小。对象只包含数据,,每个具体对象需要自己类数据的副本;编译器只创建独立于类的所有对象的成员函数的一份副本,该类的所有对象共享这份副本。

  函数作用域中定义了与类作用域同名的变量时,可以类名::变量名引用类变量。

 

  析构函数。不接受任何参数,也不可以指定返回类型。一个类只允许有一个,必须是public的,且不能重载。对象撤销时,析构函数会隐式地调用。它本身本身并不释放对象占用的内存空间,只是在系统收回对象的内存空间之前执行扫尾工作。若不显示提供,编译器会生成一个”空的“析构函数。  一般而言,析构函数的调用顺序与相应的构造函数的调用顺序相反,但是对象的存储类别可以改变析构函数的调用顺序。全局作用域定义的对象的析构函数在main函数执行时调用。Exit函数迫使程序立即结束,不执行自动对象的析构函数;abort函数迫使立即停止,且不允许调用任何对象的析构函数。

 

   默认构造函数。编译器给每个没有显示声明构造函数的类一个没有形参的默认构造函数。当类有显示的构造函数时,编译器不再提供默认构造函数。类也可以自定义默认构造函数,如

Apple(double price =3.5, int count = 0); //default construct

  

  默认的逐个成员赋值 & 复制构造函数。”=”可以将一个对象赋值给另一同类型的对象,默认这样的赋值通过逐个数据成员赋值的方式进行。对象也可以作为参数(默认按值传递),传递和返回对象的一个副本,C++将创建一个新的对象,并使用复制构造函数将原始对象的值复制到新的对象中。对每个类,编译器都提供了一个默认的复制构造函数,同逐个成员赋值一样,当所用类的数据成员包含指向动态内存分配内存的指针时,会引发严重问题。所以常需自定义复制构造函数。可以自定义复制构造函数,如声明一个自定义的array类:

1 class Array
2 {
3 public:
4     Array( int = 10 ); // 默认构造函数
5     Array( const Array &); // 自定义的复制构造函数
6      //……………
7 };
8  //……………
9 Array arr2( arr1 );

  上面的声明改成Array arr2 = arr1,同样可以调用复制构造函数。注意这里的等号并不是赋值运算符,当等号出现在对象声明中时,他调用该对象的构造函数,这种形式可以用来向构造函数传递单个参数。 其实,无论何时需要对象的副本,例如在向函数按值传递对象,从函数返回对象,或者用同一类的另一对象初始化一个对象时,都会调用复制构造函数。默认的复制构造函数的参数应该是一个const引用,以允许复制const对象;必须按引用接收参数,而非按值,否则,复制构造函数的调用会导致无穷递归(因为按值接收对象,需要复制构造函数生成实参对象的副本,而这又要调用复制构造函数),这是一个致命的逻辑错误。

 

  Const对象与const成员函数。将变量和对象声明为const可以提高性能,编译器可以对常量提供对某些变量来说不能提供的优化。Const对象只允许调用const成员函数,但允许非const函数构造函数和析构函数修改自身(否则无法初始化)。Const成员函数也只能调用const成员函数;将修改对象的数据成员的成员函数定义为const导致编译错误。

1 int getHour() const;
2 //………
3 int Time::getHour() const
4 {………}

  每个数据成员都可以使用成员初始化器初始化,但常量数据成员(const对象和const变量)和声明为引用的数据成员必须使用成员初始化器进行初始化,在构造函数中为这些数据赋值是不允许。

 1 class Apple
 2 {
 3 //
 4 private:
 5     const double price;
 6     int count;
 7 };
 8 
 9 //……
10 Apple::Apple(double p, int c)
11 : price(p) ,
12   count(c)
13 {…}

  将所有运行时不修改对象的成员函数都声明为const是一个好的习惯,防止不经意间修改对象,也可以在创建相应的const对象时调用该方法。

      成员对象以在类中声明的顺序(而非构造函数的成员初始化器表中列出的顺序)且在宿主对象构造之前建立。如果不使用成员初始化器对成员对象进行初始化(默认复制构造函数),而类定义了一个或多个构造函数,但没有一个是默认构造函数时,会产生一个编译错误。通过成员初始化器显示初始化成员对象是好的习惯。

     

  友元函数与友元类。定义在类的作用域之外,却有访问其非public和public成员的权限。在类定义中将某函数显示声明为该类的友元,要在函数原型前加friend。

 1 class Apple
 2 {
 3     friend void changeCount(Count &, int); //声明为友元
 4 
 5     friend class Banana; //声明类Banana的所有成员函数为Apple类的友元
 6 public:
 7 //……………
 8 private:
 9     int count;
10 };

 

1 void changeCount(Count &, int val) //这个可以放在Apple.cpp中定义
2 {
3     c.count = val; //引用其私有数据成员
4 }

  友元不是成员函数,类中private,public和protected等成员访问说明符与友元声明无关,友元定义可以放在类定义的任何地方,但在这些说明符之前声明友元是好的习惯。友元关系不是对称的也不是传递的。

 

(*this).member; //()是必须的,因为“ . ”的优先级高于“ * ”

  this指针本身不是对象的一部分,其所占内存大小不会再对象大小中显示。相反,this指针作为一个隐式的参数被编译器传递给对象的每个非static成员函数,所以成员函数知道要操作哪个对象的数据成员(因为成员函数只有一份副本,被所有对象共享)。This指针的类型取决于对象类型和使用this的成员函数是否声明为const。例如,在Apple的非const成员函数中,其类型是Apple* const(一个指向非const Apple对象的const指针);在Apple的const成员函数中,其类型是const Apple* const(一个指向const Apple对象的const指针)。

1 Apple &Apple::setValue(double p, int count)  //返回自身的引用
2 {
3     // …………………;
4     return *this;
5 }

有了上述后支持串行调用:

redApple. setValue(2.0, 5). setValue(6.5, 8). setValue(5.2, 5);

 

         static成员。即使没有类的任何对象,类的static成员任然存在。可以通过类名::public static成员名的方式访问,当然也可以通过具体对象按照老规矩使用。而要想访问其private/protected的static成员,应提供public static成员函数!每个static成员函数都是类的而不是对象的一项服务。Static成员函数不允许访问所以非static成员,static成员函数不具有this指针;将static成员函数声明为const是一个编译错误,因为const限定符指示函数不能修改它操作的具体对象的内容。如果成员函数不访问类的非static成员,那最好声明为static。

         此外,只要在.h文件的类定义中显示声明static就可以了,不能再在.cpp中将它们声明为static。因为将static应用到文件作用域的某个元素时,该元素将只在该文件中是已知的,而类的static成员需要在任何文件的客户代码使用(在全局名字空间范围内定义静态数据成员时包含static是一个编译错误)。static数据成员的初始化不能在构造函数中完成(与对象无关)。

 1 //.h文件
 2 class Apple
 3 {
 4 //……
 5 private:
 6     static int count;
 7 };
 8 
 9 //.cpp文件
10 int Apple::count = 1; //没有static关键字

 

 

  代理类。即使是类的private数据,也可以向类的客户隐藏。

1 // implementation.h中
2 class Implementation
3 {……}; //具体实现

 

当类定义仅使用另一个类的指针或引用时,无需包含.h,只需简单地提前类声明将其声明为一种数据类型。

 1 //Interface.h中
 2 class Implementation; 
 3 
 4 class Interface
 5 {
 6 public:
 7     //………
 8 private:
 9     Implementation *ptr;
10 };
11 
12 //Interface.cpp
13 #include” Implementation.h”
14 #include” Interface.h”
15 
16 Interface:: Interface(int v)
17          :ptr( new Implementation(v) )
18 {.....}
19 
20 Interface::setValue( v )
21 {
22          Ptr->setValue( v );
23 }
24 //……………

 

posted @ 2015-03-23 22:14  hedgehog小子  阅读(248)  评论(0编辑  收藏  举报