类和对象的进一步了解与使用

类和对象(二)

this 指针:
每个成员函数都有一个隐含的参数,指向接收消息的对象,称为this指针。
X类的this指针的类型是X*。
this指针是一个常量,含有当前实施调用的对象的地址。
不能改变this指针的值,也不能取this指针的地址。
用途:
区分与数据成员同名的变量
返回当前对象
取得当前对象地址
例:

class X {
int m;
public:
  void setVal(int m) { this -> m = m; }
  X add(const X& a)  { 
m += a.m;
return *this;	 	//返回当前对象
}
void copy(const X& a) {	//复制对象
  if (this == &a)		//同一对象,无需复制
    return;
  m = a.m;			//拷贝复制
}
};

访问器和修改器:
与直接访问数据成员相比,访问器和修改器更好地体现了封装性
也可以在修改器中进行数据有效性的验证,从而确保对象不会因外部修改而处于无效的状态。
常以一对getX()和setX() 函数的形式出现。
例:

struct Rectangle {
	double area();
	double perimeter();
//width 的访问器和修改器
	double getWidth(){return width;}
	void setWidth(double newWid)
		{ if(newWid > 0) width = newWid;	}
//height 的访问器和修改器
	double getHeight(){return height;}
	void setHeight(double newHei)
		{ if(newHei > 0) height = newHei; }
private:
	double width;
	double height;
}

友元:
在某些情况下,有的函数需要访问类的私有数据,但是我们使用全局函数进行访问私有数据时,会引起编译错误,为了避免这种错误,使之可以访问私有数据,我们可以使用友元。
C++引入了friend关键字,如果想让非成员函数访问一个类中的私有数据,应该在类中将这个函数声明为friend。
一个类的友元可以访问该类的私有数据。
在声明友元时要遵循一条规则:
友元必须在被访问的类中声明。

一个类的友元可以是:
全局函数
另一个类的成员函数
另一个类
类A是类B的友元表示A的所有成员函数都是B的友元。friend关系不可传递
如果A是类B的友元,而类B是类C的友元,A不会自动成为C的友元。

应该尽量避免使用友元:
友元会破坏类的封装性,增加类之间的耦合度。

构造函数和析构函数:
构造函数在创建对象时被自动调用,负责初始化对象,构造函数的名字和类名字相同,它没有返回类型,构造函数的参数通常为数据成员提供初始值。
如果成员是const、引用,或者是未提供默认构造函数的类类型,就必须通过构造函数初始化列表提供初值
格式如下:构造函数(参数表) : 初始化列表 { 函数体 }。
例:

class X {
int m, &r;
public:
X(int v):r(m) { m = v;}
};。

构造函数中为数据成员提供初值的两种方法:

X(int v): r(m) { m = v;}	
X(int v): m(v), r(m) {}	

在构造函数的函数体中,成员m先默认初始化,再在函数体中赋值。
写在初始化列表中,直接初始化数据成员,效率更高。
例:

class X{
int a, b;			//成员声明顺序
public:
X(int val):a(val), b(a){} 	//先初始化a,再用a初始化b,如果可能的话,尽量避免用某些成员初始化其他成员
};
//下面的形式更好一些: 用val 初始化,没有成员的依赖
X(int val) : a(val), b(val){}
//下面的形式可能会产生未定义的行为:试图用未定义的值b初始化a
X(int val) : b(val), a(b){} 	//编译器会警告,成员初始化的顺序与它们在类定义中出现的顺序一致。

对象的销毁和清除:
在对象生存期间,构造函数或其他成员函数可能为对象分配某些资源,例如为指针成员在动态存储区分配空间,当对象生存期结束时,应返回或释放相关资源。

析构函数:
析构函数主要被用来放弃在类对象的构造函数或生存期中获得的资源。
当对象离开作用域时,或者用delete 释放在堆上创建的对象时,析构函数都会被自动调用。
析构函数的名字是类名字前加波浪线“~”。
析构函数不能重载,只能为一个类定义唯一一个析构函数。
如果类中没有定义析构函数,编译器在需要时会自动合成一个析构函数。

构造函数和析构函数的调用:
程序中无论以何种形式创建对象,都会调用构造函数,各种初始化方式都会引起相应的构造函数调用:堆上的对象,数组元素对象都要调用构造函数初始化。
当对象生命期结束时,则会调用析构函数,析构函数绝大多数情况下都被自动地隐式调用,一般不要显式调用。

委托构造函数:
委托构造函数使用所属类的其他构造函数执行自己的初始化过程,把部分或全部职责委托给了其他构造函数。
语法形式:
ClassName(参数表):ClassName(参数表){函数体}

const数据成员:
在数据成员声明前加const 关键字就将其限定为常量,创建对象时初始化其中的const 数据成员,之后const 成员的值在对象的整个生存期中都不会改变。
const 数据成员要在构造函数的初始化列表中初始化。
const成员函数:
将一个成员函数声明为const,表明这个成员函数不会修改对象的数据成员,能保证对象的常量性。
声明const成员函数的语法形式:
返回类型 成员函数名(参数表) const;
定义const成员函数的语法形式:
返回类型 成员函数名(参数表) const { 函数体 }
注意const成员函数声明和定义的语法:
对于在类外定义的const成员函数,必须在它的定义和声明中同时指定关键字const。
例:

class X{
int m;
public:
X(int v = 0):m(v){}
void set(int v){ m = v;}
int get()const{ return m; }
};
……
const X b(5);			//const对象,类的对象也可以由const 限定为常量,试图修改const 对象的操作会引起编译错误。
b.get();				//OK
b.set(10);				//Error

const 成员函数的定义和调用规则:
如果成员函数是非const 的,则只有非const 对象可以调用它;const 对象不能调用非const 的成员函数。
如果成员函数是const 的,则const 对象可以调用它;非const 对象也可以调用它,不会改变对象中的成员。

指向成员的指针:
我们使用”.”或”->”表示指向该类对象的成员,当我们想要用指针获得该成员时,我们可以进行如下操作:
如果有一个指向类成员的指针p,要取得指针指向的内容,必须用"解*"运算符解引用。
p是一个类的成员,不能直接使用,必须指定对象或指向对象的指针来选择这个成员。
使用指向数据成员的指针的语法应该如下:
对象.
指向成员的指针
对象指针 ->* 指向成员的指针
定义:
语法形式
成员类型 类名字::*指向成员的指针;
例如:int Simple::*pa; //定义了一个指向Simple类中的int成员的指针,它可以指向Simple类中的任何int成员。
例:

struct Simple { int a; };
int main() {
  Simple so, *sp = &so;
  sp->a;		
  so.a;	
//如果pa是指向Simple成员a的指针
//通过对象so选择pa指向的成员:
so.*pa;	
//通过指针sp选择pa指向的成员:
sp->*pa;
}

定义指向成员函数的指针时也要指明成员函数的类类型。
基本语法:
返回类型 (类名::*指向成员函数的指针)(参数表);
例:

//成员函数指针的定义和使用语法
class Simple
{ 
public: 
  int f(float) const { return 1; }
};
int (Simple::*fp)(float) const;
int (Simple::*fp2)(float) const = &Simple::f;
int main() {
  fp = &Simple::f;	//获取成员函数的地址必须使用取地址符
} 

猜你喜欢

转载自blog.csdn.net/qq_42785226/article/details/89303761