类对象其它成员及其初始化
类的 const 成员
const 数据成员
只能同过构造函数初始值列表对 const 数据成员进行初始化。
cpp
class Box {
private:
const int length; //长度
const int width; //宽度
const int height; //高度
public:
Box();
Box(int H, int W, int L);
};
Box::Box(int H, int W, int L) : height{ H }, width{ W }, length{ L } {}
Box::Box() : height{ 1 }, width{ 2 }, length{ 3 } {}
const 数据成员可以设置类内初始值。
cpp
class Box {
private:
const int length = 3; //长度
const int width = 4; //宽度
const int height = 5; //高度
public:
Box() = default;
Box(int H, int W, int L);
};
Box::Box(int H, int W, int L) : height{ H }, width{ W }, length{ L } {}
const 成员函数
在函数的参数列表后面添加 const 关键字,这样使用 const 的成员函数被称作常量成员函数(const member function)。
const 成员函数只能引用本类中的数据成员,而不能修改它们。
cpp
class Box {
private:
const int length; //长度
const int width; //宽度
const int height; //高度
public:
Box() = default;
Box(int H, int W, int L);
void Print(void) const; //声明,打印长,宽,高
};
Box::Box(int H, int W, int L) : height{ H }, width{ W }, length{ L } {}
void Box::Print(void) const //定义也用 const 修饰
{
cout << length << ' ' << width << ' ' << height << endl;
}
const 成员函数只能能调用本类中的 const 成员函数。
一个 const 成员函数如果以引用的形式返回*this
,那么它的返回类型将是常量引用。
cpp
class Box {
private:
int length; //长度
int width; //宽度
int height; //高度
public:
Box() = default;
Box(int H, int W, int L);
const Box & Print(void) const; //返回常量引用
};
Box::Box(int H, int W, int L) : height{ H }, width{ W }, length{ L } {}
const Box & Box::Print(void) const //返回常量引用
{
cout << length << ' ' << width << ' ' << height << endl;
return *this;
}
构造函数不能声明为 const 的。
mutable 数据成员
如果希望通过 const 成员函数修改数据成员,可以将数据成员声明为 mutable 的。
cpp
class Box {
private:
int length; //长度
int width; //宽度
mutable int height; //高度,声明为 mutable
public:
Box() = default;
Box(int H, int W, int L);
int Volume(int h) const; //修改盒子高度,并求体积
};
Box::Box(int H, int W, int L) : height{ H }, width{ W }, length{ L } {}
int Box::Volume(int h) const //修改盒子高度,并求体积
{
height = h; //盒子高度可修改
return length * width * height;
}
const 对象
定义对象时可以加关键字 const,指定对象为 const 对象。
const 对象必须要有初值,对象中的所有数据成员都不能被修改。
const 对象只能调用它的 const 成员函数(除了析构和构造),const 成员函数是 const 对象的唯一对外接口。
const 成员函数可以访问 const 对象中的数据成员,但仍然不允许修改 const 对象中数据成员的值。
cpp
const Box B1; //调用无参构造
const Box B2{1,2,3}; //调用有参构造
B1.Print(); //调用 const 成员函数
B1.Volume(10); //可以修改 mutable 数据成员
聚合类
聚合类(aggregate class)使得用户可以直接访问其成员,并且具有特殊的初始化语法形式。
当一个类满足如下条件时,我们说它是聚合的:
- 所有成员都是 public 的。
- 没有定义任何构造函数。
- 没有类内初始值。
- 没有基类,也没有虚函数。
字面值常量类
数据成员都是字面值类型的聚合类是字面值常量类。
如果一个类不是聚合类,但它符合下述要求,则它也是一个字面值常量类:
- 数据成员都必须是字面值类型。
- 类必须至少含有一个 constexpr 构造函数。
- 如果一个数据成员含有类内初始值,则内置类型成员的初始值必须是一条常量表达式;或者如果成员属于某种类类型,则初始值必须使用成员自己的 constexpr 构造函数。
- 类必须使用析构函数的默认定义。
constexpr 构造函数
尽管构造函数不能是 const 的,但是字面值常量类的构造函数可以是 constexpr 函数。
constexpr 构造函数必须初始化所有数据成员,初始值或者使用 constexpr 构造函数,或者是一条常量表达式。
constexpr 构造函数用于生成 constexpr 对象以及 constexpr 函数的参数或返回类型。
一个字面值常量类
cpp
class Birthday
{
private:
unsigned int year = 0; //年
unsigned int month = 0; //月
unsigned int day =0; //日
public:
constexpr Birthday() = default;
constexpr Birthday(unsigned int y, unsigned int m, unsigned int d); //constexpr 构造函数
void Print(void) const;
};
constexpr Birthday::Birthday(unsigned int y, unsigned int m, unsigned int d) :
year{ y }, month{ m }, day{ d } {}
void Birthday::Print(void) const
{
cout << year << " 年 " << month << " 月 " << day<< " 日" << endl;
}
constexpr 对象
constexpr对象只能调用它的 constexpr 成员函数。
constexpr对象只能调用构造函数创建。
cpp
constexpr Birthday b{ 2012,3,12 };
b.Print();
静态成员
静态数据成员
静态数据成员不能使用构造函数进行初始化,只能在类体外初始化。
在类外初始化静态数据成员时,不能重复 static 关键字。
cpp
class Box {
private:
int length; //长度
int width; //宽度
int height; //高度
static int number; //统计盒子个数
public:
Box();
Box(int H, int W, int L);
};
int Box::number = 0; //类外初始化静态数据成员
const 静态数据成员可以指定类内初始值。
cpp
class Box {
private:
int length; //长度
int width; //宽度
int height; //高度
const static int number = 0; //const 静态数据成员
public:
Box();
Box(int H, int W, int L);
};
静态数据成员在程序运行开始时被分配空间,程序结束时释放空间。
该类的所有对象共享一个或多个静态数据成员。
静态成员函数
静态成员函数不与任何对象绑定,没有 this 指针,不能访问本类中非静态成员。
静态成员函数不能声明成 const 的。
cpp
class Box {
private:
int length; //长度
int width; //宽度
int height; //高度
static int number; //统计盒子个数
public:
Box();
Box(int H, int W, int L);
static int GetNumber(void); //静态成员函数
};
int Box::number = 0;
Box::Box(int H, int W, int L) : height{ H }, width{ W }, length{ L }
{
number += 1; //每创建一个盒子number加一
}
Box::Box() : height{ 1 }, width{ 2 }, length{ 3 }
{
number += 1; //每创建一个盒子number加一
}
int Box::GetNumber(void) //静态成员函数
{
return number;
}
没有定义对象,静态成员也可以通过类名引用。
虽然静态成员不属于类的某个对象,但是我们仍然可以使用类的对象、引用或者指针来访问静态成员。
cpp
int main()
{
cout << Box::GetNumber() << endl;
//没有对象生成,number = 0;
Box B1;
Box B2{ 1,1,1};
cout << B2.GetNumber() << endl;
//生成了两个对象,number = 2;
return 0;
}
在类外定义静态成员时,不能重复 static 关键字。
友元
友元(friend )机制允许一个类授权其他的函数或类访问它的私有成员。
friend 关键字只能出现在声明中。
可以在类声明中,声明一个全局函数为友元函数。
可以在类声明中,声明其他类为友元类。
可以在类声明中,声明其他类中的函数为友元函数。
一般来说,最好在类定义开始或结束前的位置集中声明友元。