特殊数据成员的初始化
大约 4 分钟
特殊数据成员的初始化
在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;
};
引用数据成员
和常量成员相同,引用成员也必须在构造函数初始化列表中进行初始化,否则编译报错。
#include <iostream>
using std::cout;
using std::endl;
class Point
{
public:
Point(int ix = 0, int iy = 0)
: _ix(ix)
, _iy(iy)
, _ref(_ix)
{
cout << "Point(int = 0, int = 0)" << endl;
/* _ix = ix;//error,赋值 */
/* _iy = iy; */
}
void print()
{
cout << "(" << _ix << ", "
<< _iy << ")" << endl;
}
~Point()
{
cout << "~Point()" << endl;
}
private:
int _ix;
int _iy;
int &_ref;
};
//成员函数不占用类的大小,成员函数存在于程序代码区,被该类的
//左右对象共享
//
int main(int argc, char **argv)
{
cout << "sizeof(Point) = " << sizeof(Point) << endl;
Point pt(1, 2);//栈对象
return 0;
}
$./a.out
sizeof(Point) = 16 #有内存对齐
Point(int = 0, int = 0)
~Point()
类对象成员
当数据成员本身也是自定义类类型对象时,比如一个直线类Line对象中包含两个Point类对象,对Point 对象的创建就必须要放在Line的构造函数的初始化列表中进行。如
#include <iostream>
using std::cout;
using std::endl;
class Point
{
public:
/* Point(int ix = 0, int iy = 0) */
Point(int ix, int iy)
: _ix(ix)
, _iy(iy)
{
cout << "Point(int = 0, int = 0)" << endl;
}
void print()
{
cout << "(" << _ix << ", "
<< _iy << ")" << endl;
}
~Point()
{
cout << "~Point()" << endl;
}
private:
int _ix;
int _iy;
};
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();
_pt2.print();
}
~Line()
{
cout << "~Line()" << endl;
}
private:
Point _pt1;//类对象成员(子对象)
Point _pt2;
};
int main(int argc, char **argv)
{
Line line(1, 2, 3, 4);
line.printLine();
return 0;
}
当Line的构造函数没有在其初始化列表中初始化对象_pt1
和_pt2
时,系统也会自动调用Point类的默认构造函数,此时就会与预期的构造不一致。因此需要显式在Line的构造函数初始化列表中初始化_pt1
和_pt2
对象。
静态数据成员
C++允许使用static(静态存储)修饰数据成员,这样的成员在**就被创建并初始化的(与之相比,对象是在**被创建的),且其实例只有一个,被所有该类的对象共享,就像住在同一宿舍里的同学共享一个房间号一样。静态数据成员和之前介绍的静态变量一样,当程序执行时,该成员已经存在,一直到程序结束,任何该类对象都可对其进行访问,静态数据成员存储在全局/静态区,并不占据对象的存储空间。
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; //4和 _brand 会有内存对齐
static double _totalPrice;//4静态的数据成员不占类的大小,被类
//创建的所有对象所共享
};
因为静态数据成员不属于类的任何一个对象,所以它们并不是在创建类对象时被定义的。这意味着它们不是由类的的构造函数初始化的,一般来说,我们不能在类的内部初始化静态数据成员,必须在类的外部定义和初始化静态数据成员,且,格式如下:
类型 类名::变量名 = 初始化表达式; //普通变量
类型 类名::对象名(构造参数); //对象变量
//静态数据成员要放在全局静态位置进行初始化,特别是对于头文件与
//实现文件的形式,要放在实现文件里面,否则会有多重定义的报错
double Computer::_totalPrice = 0;
注意:要放在里面,否则会有的报错