一、常对象、常数据成员和常成员函数
既要使得数据能够在函数间共享,又要保证它不能被任意的修改,使用const限定,将其改为只读的。
常对象:
类名 const 对象名1(实参列表), 对象名2,......;
const 类名 对象名1(实参列表), 对象名2,......;
二者意义相同,表示该对象是一个const对象,只可读,不可写。
常对象中除了默认构造函数和析构函数外,只有用const限定过的成员函数才能够被调用。
非const函数不能被调用。
使用mutable修饰常对象中的数据成员,能够使得系统获得更改这一成员的权限,在实际应用中具有一定的价值。
常数据成员:在声明数据成员的时候使用const限定,如 const int a;
常数据成员不能被成员函数和非成员函数修改,只有构造函数的初始化列表能对其进行初始化。
class 类名 { //类体
…返回类型 函数名(形式参数列表) const //常成员函数定义
{
函数体
}…
};
class 类名 { //类体
…返回类型 函数名(类型1 参数名1,类型2 参数名2,…) const; …
};
返回类型 类名::函数名(形式参数列表) const //常成员函数外部定义
{
函数体
}
无论是声明还是定义常成员函数,都需要用const限定,若const写到返回类型前面,表示返回的数值是不可改的。
数据成员 | 非常成员函数 | 常成员函数 |
非常数据成员 | 允许访问、可以修改 | 允许访问、不能修改 |
常数据成员 | 允许访问、不能修改 | 允许访问、不能修改 |
常对象数据成员 | 不能访问、不能修改 | 允许访问、不能修改 |
1.在一个类中,如果有些数据成员的值允许修改,另一些数据 成员的值不允许修改,那么可以将一部分数据成员声明为const (常数据成员),使得其值不能被修改。而普通的成员函数可以修 改普通的数据成员,但只能访问常数据成员的值。
2.如果要求所有数据成员的值都不允许改变,可以将对象声明 为const的(常对象),那么只能用const成员函数访问数据成员, 且不能修改其值。这样,数据成员无论如何也不会被修改。
3.如果定义了一个常对象,只能调用其中的const成员函数,而 不能调用非const成员函数。如果需要访问对象中的数据成员,可将常对象中所有成员函数都声明为const成员函数,但应确保在函 数中不会修改对象中的数据成员。
4.常对象中的成员函数不一定是常成员函数。如果在常对象中 的成员函数未加const声明,C++把它作为非常成员函数处理
5.常成员函数不能调用另一个非常成员函数。
二、常指针
类名 * const 指针变量名=对象地址; //常指针
始终保持其初值,不能修改指向,定义时就要初始化。指向对象的常指针。
常指针指向的对象可以是非常对象。常作为函数的形参使用。
const 类名 *指针变量名;
指向常对象的指针变量,不能通过该指针去修改指向的对象的值。但指针本身非常指针,可以任意改变指向。因此可以在定义的时候不初始化。
只要我们定义的指针是常对象指针,即使其指向的对象是非常对象,也不能通过该指针改变对象的内容。
该指针作为形参为了保护所指向的对象,不被修改。
三、常引用
const 类名 & 引用变量名;
既可以不生成对象的副本,作为形参,大大减少了空间,又可以保护原对象不被改变。还能够生成一个自己用的名字。
四、静态成员
static int count;
►①静态成员的名字是在类的作用域中,因此可以避免与其他类的成 员或全局对象名字冲突;
►②静态成员可以实施封装,可以是私有成员,而全局对象不可以。
►③静态成员是与特定类关联的,结构清晰。
静态数据成员是属于整个类的,他可以被该类下的任何对象调用。在该类中改变,在所有对象中都可以改变,但是不占用额外的空间,只占用一份空间。
相较于全局变量,他的作用域只在类中,更安全, 也简介。
同时可以在构造函数中对这个静态成员改变,例如每生成一个对象,都对count++。
►关于静态数据成员的说明:
►(1)通常,非静态数据成员存在于类类型的每个对象中,静态数据成员则独立于该类的任何对象,在所有对象之外单独开辟空间存储。在为对象所分配的空间中不包括静态数据成员所占的空间。
►(2)如果只声明了类而未定义对象,则类的非静态数据成员是不占存储空间的,只有在定义对象时,才为对象的数据成员分配空间。 但是只要在类中定义了静态数据成员,即使不定义任何对象,也为 静态数据成员分配空间,它可以在尚未建立对象时就被引用。
►(3)访问静态成员时同样需要遵守公有及私有访问规则。
►(4)静态数据成员必须在类外部定义一次(仅有一次),静态成员不能通过类构造函数进行初始化,而是在类外定义时进行初始化。 定义静态数据成员的方式为:
数据成员类型 类名::静态数据成员名=初始化式;
他可以被用作默认实参。
可以直接通过 类名字::静态数据成员名 调用
五、静态成员函数
static int getcount() { return count; } //静态成员函数
静态成员函数也是类的一部分,直接使用类名字::函数名调用也可以直接用对象名字.函数名字调用。
静态成员函数没有this指针,因此无法访问本类中的非静态成员。
静态成员函数不能访问非静态成员。只是专门为了访问静态的数据成员的。因此他也不能被限制为const。
(谁调用非静态的成员函数,this指针就会指向谁,静态成员没有,只能访问静态的数据成员。)
在类外使用静态成员函数访问静态成员。
对象可以调用静态函数和非静态函数,
但是类的域运算符只能调用静态。
六、友元
将一个函数设置为友元函数,将一个类设置成友元类。
友元类的所有成员函数均可以访问有缘关系的类的非公有成员。
所以访问类的非公有成员具有两个用户:一个是自己类本身,一个是友元。友元关系是单向的。
#include <iostream>
#include <cmath>
using namespace std;
class Point { //Point类
public:
Point(int _x=0,int _y=0) : x(_x), y(_y) { }
private:
int x, y;//私有数据成员
friend double distance(Point& r1, Point& r2); //友元函数
};
distance函数就可以使用这个类中的私有成员x,y
class B; //类的前向声明
class A { //A类
public:
A(int _a=0) : a(_a) { }
void setb(B& r);
private:
int a; //私有数据成员
};
class B { //B类
public:
B(int _b=0) : b(_b) { }
private:
int b; //私有数据成员
friend void A::setb(B& r);
};
由于类A中函数用到了B,对B做一个前向声明,之后在B的定义中,将类A中的函数设置为B的友元函数,称之为友元成员函数。
将一个类设置成友元类,则该类中所有的成员均可以访问类中的所有成员;
class 类名 { //类体
…
friend 友类名;
};
class 友类名 { //类体
…
};
利用友元,突破封装的限制,要在数据共享和信息屏蔽之间选择恰当的平衡点。