程序设计B笔记——类(二)

本文详细介绍了C++类中的this指针用法,包括在函数返回、参数冲突时的解决以及防止重复赋值。接着探讨了复制构造函数的概念、默认行为以及何时会被自动调用。此外,还讨论了类的其他成员,如常成员(常数据成员、常对象、常成员函数)、静态成员(静态数据成员和静态成员函数)以及友元机制(友元函数和友元类)。最后,简要提及了类的包含(组合)以及成员对象的初始化与析构顺序。

6.1.3 this指针

需要显式引用this指针的三种情况
(1)在类的非静态成员函数中返回类对象本身对象的引用的时候,直接使用 return *this,返回本对象的地址时,return this。
(2)当参数与成员变量名相同时,如this->x = x,不能写成x = x。
(3)避免对同一对象进行赋值操作,判断两个对象是否相同时,使用this指针。

6.2.4 复制构造函数

复制构造函数用一个已有同类对象创建新对象进行数据初始化
C++为类提供默认版本的复制构造函数
程序员可以定义用户版本的复制构造函数
语法形式

类名 :: 类名(const  类名  &  引用名  ,  …);

复制构造函数的特点:
1.复制构造函数名与类名相同,并且也没有返回值类型。
2.复制构造函数可写在类中,也可以写在类外。
3. 复制构造函数要求有一个类类型引用参数
4. 如果没有显式定义复制构造函数,系统自动生成一个默认形式的复制构造函数。

复制构造函数的调用
以下三种情况下由编译系统自动调用:
1.声明语句中用类的一个已知对象初始化该类的另一个对象时。
2.当对象作为一个函数的实参传递给函数的形参时,需要将实参对象去初始化形参对象时,需要调用复制构造函数。
3.当对象是函数的返回值时,由于需要生成一个临时对象作为函数返回结果,系统需要将临时对象的值初始化另一个对象,需要调用复制构造函数。

浅复制与深复制
关于浅复制:
●在用一个对象初始化另一个对象时,只复制了数据成员,而没有复制资源,使两个对象同时指向了同一资源的复制方式称为浅复制。
即:对于复杂类型的数据成员只复制了存储地址没有复制存储内容
●默认复制构造函数所进行的是简单数据复制,即浅复制

关于深复制:
●通过一个对象初始化另一个对象时,不仅复制了数据成员,也复制了资源的复制方式称为深复制。
●自定义复制构造函数所进行的复制是浅复制。

定义支持深复制的复制构造函数
1.深复制构造函数必须显式定义
2.深复制构造函数的特点
定义:类名::类名([const] 类名 &对象名);
成员变量的处理:对复杂类型的成员变量,使用new操作符进行空间的申请,然后进行相关的复制操作

6.3 类的其他成员

常成员
静态成员
友元

6.3.1 常成员

1. 常数据成员
常数据成员是指数据成员在实例化被初始化后,其值不能改变。
在类的成员函数说明后面可以加const关键字,则该成员函数成为常量成员函数
如果在一个类中说明了常数据成员,那么构造函数就只能通过初始化列表对该数据成员进行初始化,而任何其他函数都不能对该成员赋值。

#include<iostream>
using namespace std;
class Mclass
{ public :
      int k;
      const int M;		//说明常数据成员
      Mclass() : M(5) { } 	//用初始式对常数据成员赋值
      void testFun()
       { //M++;	 	//错误,不能在成员函数中修改常数据成员
           k++;		//可以修改一般数据成员
       }
 } ;

2.常对象
如果在说明对象时用const修饰,则被说明的对象为常对象。
常对象的说明形式如下:
类名 const 对象名[(参数表)];
或者
const 类名 对象名[(参数表)];
在定义常对象时必须进行初始化,而且不能被更新。
说明:
(1)C++不允许直接或间接更改常对象的数据成员。
(2)C++规定常对象只能调用它的常成员函数、静态成员函数、构造函数(具有公有访问权限)。

3. 常成员函数
在类中使用关键字const说明的函数为常成员函数,常成员函数的说明格式如下:
类型说明符 函数名(参数表) const;
const是函数类型的一个组成部分,因此在函数的实现部分也要带关键字const。
常成员函数不能更新对象的数据,也不能调用非const修饰的成员函数(静态成员函数、构造函数除外)

6.3.2 静态成员

类成员冠以static声明时,称为静态成员。
静态数据成员为同类对象共享。
静态成员函数与静态数据成员协同操作。

静态成员函数
静态成员不属于某一个单独的对象,而是为类的所有对象所共有
静态成员函数的作用不是为了对象之间的沟通,而是为了能处理静态数据成员: 保证在不依赖于某个对象的情况下,访问静态数据成员

静态数据成员
静态数据成员在定义或说明时前面加关键字static,如:

class A
{
  	int n;
	static int s;
};

对于类的普通数据成员,每一个对象都各自拥有一个副本。(分配不同的存储空间)
对于静态数据成员,每个类只拥有一个副本 。(在静态存储区分配一个存储空间,对所有对象都是可见的)
公有访问权限的静态成员,可以通过下面的形式进行访问

类名::静态成员的名字
对象名.静态成员名字
对象指针->静态成员的名字
在静态成员函数内部,直接访问

静态数据成员声明及初始化
在类外进行静态数据成员的声明

类型 类名::静态数据成员[=初始化值];   //必须进行声明

不能在成员初始化列表中进行初始化
如果未进行初始化,则编译器自动赋初值(默认值是0)
初始化时不能使用访问权限

静态成员函数
除静态数据成员以外,一个类还可以有静态成员函数。
静态函数仅可以访问静态成员,
或是静态成员函数或是静态数据成员。

静态成员函数和静态数据成员一样,它们都属于类的静态成员,它们都不是对象成员。因此,对静态成员的引用不需要用对象名。
静态成员函数没有this指针,只能对静态数据操作
定义静态成员函数的格式如下:

static 返回类型 静态成员函数名(参数表);

与静态数据成员类似,调用公有静态成员函数的一般格式有如下几种:

类名::静态成员函数名(实参表)
对象. 静态成员函数名(实参表)
对象指针->静态成员函数名(实参表)

说明:
(1)静态成员函数在类外定义时不用static前缀。
(2)静态成员函数主要用来访问同一类中的静态数据成员。
(3) 私有**静态成员函数不能在类外部或用对象访问。
(4)可以在建立对象之前处理静态数据成员。
(5)编译系统将静态成员函数限定为内部连接(在其他文件中不可见)。
(6)静态成员函数中是没有this指针的。
(7)静态成员函数不访问类中的非静态数据成员。如有需要,只能通过对象名(或指向对象的指针)访问该对象的非静态成员
静态成员函数来访问非静态数据成员。

#include<iostream.h>
class small_cat{
public:
     small_cat(double w){weight=w;total_weight+=w;total_number++;}
     static void display(small_cat &w)
     {cout<<"The small_cat weights "<<w.weight<<"kg\n";}
     static void total_disp()
     {cout<<total_number<<"small_cat total weight ";
       cout<<total_weight<<" kg "<<endl;}
private:
     double weight;  
     static double total_weight;	static double total_number;
};
double small_cat::total_weight=0;double small_cat::total_number=0;
int main()
{    small_cat w1(0.9),w2(0.8),w3(0.7);
      small_cat::display(w1);
      small_cat::display(w2);
      small_cat::display(w3);
      small_cat::total_disp();
      return 0;}

  1. 友元函数
  • 如果在本类(类A)以外的其他地方定义了一个函数(函数B)
    这个函数可以是不属于任何类的非成员函数, 也可以是其他类的成员函数,
  • 在类体中用friend对其(函数B)进行声明,此函数就称为本类(类A)的友元函数。
  • 友元函数(函数B)可以访问这个类(类A)中的私有成员 class A
   { private:
          int  i ;
          friend void FriendFun(A * , int) ; 
      public:
         void MemberFun(int) ;
   } ;void FriendFun( A * ptr , int x  ) 
     { ptr -> i = x ; } ;  
void A:: MemberFun( int x ) 
     { i = x ; } ;
A Aobj ;
FriendFun( &Aobj, 5 ) ;
Aobj.MemberFun( 5 ) ;

定义一个boat类,含有weight数据成员。
定义该类的一个友元函数, 该函数能输出一个boat对象的重量

class Boat{
      int weight;
public:
   Boat(int w):weight(w){}
   friend void display_weight(Boat &a)
};
void display_weight(Boat &a){
    cout<<a.weight<<endl;}
int main(){
    Boat b(100);
    display_weight(b);
     return 0;
}

将成员函数声明为友元函数

#include <iostream>
using namespace std;
class Date;                 //对Date类的提前引用声明
class Time                  //定义Time类
{
public:
	Time(int,int,int);
	void display(Date &);    
private:
	int hour;
	int minute;
	int sec;
};
class Date                               //声明Date类
{
public:
	Date(int,int,int);
	friend void Time∷display(Date &);    //声明Time中的display函数为友元成员函数
private:
	int month, day, year;
};
Time∷Time(int h,int m,int s)    //类Time的构造函数
{
	hour=h,	minute=m,	sec=s;
}
//两个类定义的顺序不能颠倒
void Time∷display(Date &d){
	cout<<d.month<</<<d.day<</<<d.year<<endl;   
	cout<<hour<<:<<minute<<:<<sec<<endl;        
}
Date∷Date(int m,int d,int y)
{
	month=m;
	day=d;
	year=y;
}
int main( ){
	Time t1(10,13,56);             
	Date d1(12,25,2004);           
	t1.display(d1);                
	return 0;
}
  1. 友元类
    假设有如下的类的
class B
{ 
    ……………
  private:
	A obj1;
};

A是另一个类,B类的成员函数要访问A的私有成员,此时,需要在A类中,把类B声明为A的友元。

6.3.3 友元

  • 若F类是A类的友元类,则F类的所有成员函数都是A类的友元函数
  • 友元类通常设计为一种对数据操作或类之间传递消息的辅助类

友元类的声明格式:

friend class 类名; 

6.4 类的包含(类的组合)

  • 类的包含是程序设计中一种软件重用技术。即定义一个新的类时,通过编译器把另一个类 “抄”进来。
  • 当一个类中含有已经定义的类类型成员,带参数的构造函数对数据成员初始化,须使用初始化语法形式。
构造函数 ( 形参表 ) : 对象成员1(形参表 ) , … , 对象成员n (形参表 ) ;

对象成员的初始化

  • 出现成员对象时,该类的构造函数要包含对象成员的初始化。如果构造函数的成员初始化列表没有对成员对象初始化时,则使用成员对象的无参(缺省)构造函数。
  • 建立一个类的对象时,要先执行成员对象自己的构造函数,再执行当前类的构造函数。
  • 成员对象的构造函数调用次序和成员对象在类中的说明次序一致(声明顺序为:a1、b1、b2),与它们在成员初始化列表中出现的次序无关(初始化列表顺序为:b1、b2、a1)。
  • 析构函数的调用顺序相反

简单对象成员初始化

#include<iostream>
using namespace std;
class A
{ public:
     A(int x):a(x){ }
     int a ;
};
class B
{ public:
     B( int x, int y ) : aa(x)  { b = y ; }
     void out() { cout<<"aa = "<<aa.a<<endl<<"b = "<<b<<endl ; }
  private:
     int b ;
     A aa ;	
} ;
int main()
{ B objB( 3, 5 ) ;
  objB.out() ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值