目录:
| 常量数据成员 | 引用数据成员 | 类对象成员 | 静态数据成员 |
|---|
| 静态成员函数 | const 成员函数 |
|---|
特殊数据成员的初始化
在 C++ 的类中,有4种比较特殊的数据成员,他们分别是 常量成员、引用成员、类对象成员 和 静态成员,他们的初始化与普通数据成员有所不同。
常量数据成员
当数据成员用 const 关键字进行修饰以后,就成为常量成员。一经初始化,该数据成员便 具有“只读属性”,在程序中无法对其值修改。事实上,在构造函数体内初始化 const 数据成员是非法的,它们只能在构造函数初始化列表中进行初始化。如:
class Point
{
public:
//错误写法
Point(int ix = 0, int iy = 0)
{
_ix = ix; //error, 这是赋值语句,const成员不能修改
_iy = iy; //error
_iz = _ix;
}
//正确写法
Point(int ix = 0, int iy = 0)
: _ix(ix)
, _iy(iy)
, _iz(_ix)
{}
private:
const int _ix;
const int _iy;
int & _iz;
};
引用数据成员
和常量成员相同,引用成员也必须在构造函数初始化列表中进行初始化,引用作为数据成员时候,占用一个指针大小的空间
类对象成员
一个自定义的类型创建的对象作为另外一个自定义类型的数据成员(子对象)的时候,默认会调用子对象的默认(无参)的构造函数,如果我们想初始化,必须要显示调用子对象的相应构造。
即当数据成员本身也是自定义类类型对象时,比如一个直线类 Line 对象中包含两个 Point 类对象,对 Point对象的创建就必须要放在 Line 的构造函数的初始化列表中进行。如
class Line {
public:
Line(int x1, int y1, int x2, int y2)
: _pt1(x1, y1)
, _pt2(x2, y2)
{
cout << "Line(int,int,int,int)" << endl;
}
void printLine()
{
_pt1.print();
cout << "--->";
_pt2.print();
cout << endl;
}
private:
Point _pt1; //其他对象成员
Point _pt2;
};
当 Line 的构造函数没有在其初始化列表中初始化对象 _pt1 和 _pt2 时,系统也会自动调用 Point 类的 默认构造函数,此时就会与预期的构造不一致。因此需要显式在 Line 的构造函数初始化列表中初始化 _pt1 和 _pt2 对象。
静态数据成员
C++ 允许使用 static (静态存储)修饰数据成员,这样的成员在编译时就被创建并初始化的(与之相比,对象是在运行时被创建的),且其实例只有一个,被所有该类的对象共享,就像住在同一宿舍里的同学共享一个房间号一样。
静态数据成员 和之前介绍的静态变量一样,当程序执行时,该成员已经存在,一直到程序结束,任何该类对象都可对其进行访问,静态数据成员存储在全局/静态区,并不占据对象的存储空间。
下面以 Computer 为例,模拟购买电脑的过程,为了获取总价,我们定义一个静态变量 _totalPrice :
class Computer {
public:
Computer(const char * brand, double price)
: _brand(new char[strlen(brand) + 1]())
_price(price)
{
_totalPrice += _price;
}
void print()
{
cout << "品牌:" << _brand << endl
<< "价格:" << _price << endl
<< "总价:" << _totalPrice << endl;
}
//...
private:
char * _brand;
double _price;
static double _totalPrice; //全局静态,头文件中
};
因为静态数据成员不属于类的任何一个对象,所以它们并不是在创建类对象时被定义的。这意味着它们不是由类的的构造函数初始化的,一般来说,我们不能在类的内部初始化静态数据成员,必须在类的外部定义和初始化静态数据成员,且不再包含 static 关键字,格式如下:
类型 类名::变量名 = 初始化表达式; //普通变量
类型 类名::对象名(构造参数); //对象变量
Computer 中的静态变量 _totalPrice 的初始化如下:
//静态数据成员必须放到类外部进行初始化
double Computer::_totalPrice = 0; //定义文件中
特殊的成员函数
除了特殊的数据成员以外, C++ 类中还有两种特殊的成员函数:静态成员函数 和 const 成员函数。
先看静态成员函数。
静态成员函数
成员函数也可以定义成静态的,静态成员函数的特点:
- 静态成员函数内部不能使用非静态的成员变量和非静态的成员函数
- 静态成员函数内部只能调用静态数据成员和静态的成员函数
- 如果非要 静态成员函数中访问非静态成员,可以传参
原因在于静态成员函数的参数列表中不含有隐含的 this 指针,如下:
class Computer
{
public:
Computer(const char * brand, double price)
: _brand(new char[strlen(brand) + 1]())
, _price(price)
{
_totalPrice += _price;
}
//...
void printTotalPrice()
{
cout << "总价:" << _totalPrice << endl;
}
//...
private:
char * _brand;
double _price;
static double _totalPrice;
};
对于静态成员函数,还可以直接通过类名进行调用,这也是最常用的方式:
int main(void)
{
Computer pc1("Huawei MateBook14", 5699);
pc1.print();
Computer::printTotalPrice();//通过类名直接调用
return 0;
}
下面再来看一个有意思的例子:
class NullPointCall
{
public:
static void test1();
void test2();
void test3(int test);
void test4();
private:
static int _static;
int _test;
};
int NullPointCall::_static = 0;
void NullPointCall::test1()
{
cout << "_static = " << _static << endl;
}
void NullPointCall::test2()
{
cout << "coding is very cool!" << endl;
}
void NullPointCall::test3(int test)
{
cout << "test = " << test << endl;
}
void NullPointCall::test4()
{
cout << "_test = " << _test << endl;
}
int main(void)
{
NullPointCall * pNull = nullptr;
pNull->test1();
pNUll->test2();
pNull->test3(10);
pNull->test4();
return 0;
}
运行结果

程序中直接通过类名进行调用 text4,在 text4 函数中调用了非静态成员
const 成员函数
之前已经介绍了 const 在函数中的应用,实际上, const 在类成员函数中还有种特殊的用法,把 const 关键字放在函数的参数表和函数体之间(与之前介绍的 const 放在函数前修饰返回值不同), 称为 const 成员函数,其具有以下特点:
- 只能读取类数据成员,而不能修改之。
- 只能调用 const 成员函数,不能调用非 const 成员函数。
- const 成员函数与非const成员函数可以 进行重载,且const成员函数不能修改数据成员
- 非const对象可以调用两种,但是默认调用非const成员函数
- const对象只能调用const成员函数
其格式为:
类型 函数名(参数列表) const
{
函数体
}
比如当给 Computer 类添加一个 const 的打印函数后,则其实现如下:
class Computer
{
public:
//...
void print() const
{
cout << "品牌:" << _brand << endl
<< "价格:" << _price << endl;
}
//也可以是
//void print() const
//{
// cout << "(" << this->_brand
// << ", " << this->_brand
// << ")" << endl;
//}
//非 const
void print2()
{
cout << "品牌:" << _brand << endl
<< "价格:" << _price << endl;
}
//...
};
有以下情况:
Computer com1("Thinkpad", 8000);
//默认情况下,非 const对象可以调用非 const版本的成员函数
com1.print2();
//非 const对象可以调用 const版本的成员函数
com1.print();
const Computer com2("MI", 5000);
//const对象可以调用 const版本的成员函数
com2.print();
//const对象不可以调用非 const版本的成员函数
//com2.print2();
本文深入探讨了C++中四种特殊数据成员:常量成员、引用成员、类对象成员和静态成员的初始化方法,以及静态成员函数和const成员函数的特性和使用方式。

415

被折叠的 条评论
为什么被折叠?



