【学习C++】学习C++ -> 类的特殊数据成员
来源:互联网 发布:2017淘宝网店数量 编辑:程序博客网 时间:2024/06/01 15:54
学习C++ -> 类的特殊数据成员
转载 http://www.cnblogs.com/mr-wid/archive/2013/02/23/2923842.html
在构造函数一节的介绍中, 我们已经提到了在C++中有几类特殊的数据成员不能使用构造函数进行初始化, 他们有自己的初始化方式, 下面就具体介绍下这几种数据成员。
一、const 数据成员
const 类型的数据成员具有只读属性, 在构造函数内进行初始化是不允许的, 例如以下代码:
1 #include <iostream> 2 3 using namespace std; 4 5 class A 6 { 7 public: 8 A(int n = 0) { num = n; } //在构造函数内使用 n 初始化const型数据成员 num 9 void showNum() { cout<<"num = "<<num<<endl; }10 private:11 const int num; //const 型数据成员12 };13 14 int main()15 {16 A a(10);17 a.showNum();18 19 return 0;20 }
尝试编译运行时报错:
error: uninitialized member 'A::num' with 'const' type 'const int' error: assignment of read-only data-member 'A::num'
要初始化 const 型的数据成员, 必须通过初始化表达式来进行初始化, 一经初始化, 其值确定, 不能再被修改, 通过初始化表达式形式如下:
1 #include <iostream> 2 3 using namespace std; 4 5 class A 6 { 7 public: 8 A(int n = 0):num(n) { } //使用初始化表达式对const型数据成员进行初始化 9 void showNum() { cout<<"num = "<<num<<endl; }10 private:11 const int num;12 };13 14 int main()15 {16 A a(10);17 a.showNum();18 19 return 0;20 }
二、引用类型的成员
对于引用类型的成员, 同样只能通过初始化表达式进行初始化, 错误的示例这里不再举出, 一个通过初始化表对引用类型初始化的示例:
1 #include <iostream> 2 3 using namespace std; 4 5 class A 6 { 7 public: 8 A(int &rn):rNum(rn) { } //使用初始化表达式对引用型数据成员进行初始化 9 void showNum() { cout<<"num = "<<rNum<<endl; }10 private:11 int &rNum; //引用类型12 };13 14 int main()15 {16 int x = 10, &rx = x;17 A a(rx); //传递引用类型18 a.showNum();19 20 return 0;21 }
三、类对象成员
类的对象可以作为另一个类的数据成员, 在定义类时, 与普通的数据成员一样, 在声明时无法进行初始化, 例如有个Line类中有两个 Point 类的对象作为数据成员, 在声明时
private: int xPos(10, 20); int yPos(100, 200);
这样是错误的, 所以在初始化类对象成员时也需要一定的方法。
情况一:
还以 Line 类和 Point 类为例, 当 Point 类中的数据成员全部为 public 时, 可以在 Line 类的构造函数内完成初始化, 像以下示例的情况:
1 #include <iostream> 2 3 using namespace std; 4 5 class Point 6 { 7 public: 8 void printPoint() { cout<<"("<<xPos<<", "<<yPos<<")\n"; } 9 int xPos; //public类型的 xPos 和 yPos10 int yPos;11 };12 13 class Line14 {15 public:16 Line(int x1, int y1, int x2, int y2)17 {18 M.xPos = x1; M.yPos = y1; //在构造函数内完成类对象的初始化19 N.xPos = x2; N.yPos = y2;20 }21 void printLine() { M.printPoint(); N.printPoint(); }22 private:23 Point M; //类对象成员, M和N24 Point N;25 };26 27 int main()28 {29 Line L(10, 20, 100, 200);30 L.printLine();31 32 return 0;33 }
编译运行的结果:
(10, 20) (100, 200) Process returned 0 (0x0) execution time : 0.500 s Press any key to continue.
代码说明:
由于 Point 类中的数据成员全为 public 的, 所以可以通过 对象名.数据成员名 的方式直接进行访问。 可以看到, Line 类中有两个 Point 类型的数据成员, M和N, 然后通过 对象名.数据成员名 的方式在 Line 类的构造函数中完成初始化。
情况二:
由于类的数据成员一般都为 private 型的, 再使用上面的方式进行初始化就不适合了, 因为 private 数据是不允许外部直接访问的, 将 Point 类中的数据成员改为 private 后再编译运行代码便会报出error: 'int Point::xPos' is private 这样的错误。
要在 Line 类中对 Point 的 private 数据成员进行正常的初始化同样需要借助初始化表达式来完成, 修改后的示例:
1 #include <iostream> 2 3 using namespace std; 4 5 class Point 6 { 7 public: 8 Point(int x, int y) { xPos = x; yPos = y; } 9 void printPoint() { cout<<"("<<xPos<<", "<<yPos<<")\n"; }10 private:11 int xPos; //private类型的 xPos 和 yPos12 int yPos;13 };14 15 class Line16 {17 public:18 Line(int x1, int y1, int x2, int y2):M(10, 20), N(100, 200) { ; } //借助初始化表达式完成对M,N的初始化19 void printLine() { M.printPoint(); N.printPoint(); }20 private:21 Point M; //类对象成员, M和N22 Point N;23 };24 25 int main()26 {27 Line L(10, 20, 100, 200);28 L.printLine();29 30 return 0;31 }
运行输出后的结果与上例中是相同的。
代码说明:
通过初始化表达式对象 L 中的 M、N 数据成员的初始化顺序如下: 首先 M 对象的构造函数被调用, 接着调用 N 对象的构造函数, 最后 Line 类的构造函数被调用, 这样便完成了类对象成员的初始化。
四、static类型数据成员
static 类型的数据成员为静态成员, 他的特点是: 无论对象创建了多少个, 该数据成员的实例只有一个, 会被该类所创建的所有对象共享, 其中任何一个对象对其操作都会影响到其他对象。该类型的数据初始化是放在类外进行的, 其基本格式如下:
类型 类名::成员变量名 = 初始化值/表达式;
一个示例: 统计一共创建了多少个对象, 并且在一番销毁后还剩多少。
1 #include <iostream> 2 3 using namespace std; 4 5 class Book 6 { 7 public: 8 Book() { ibookNumber++; } //通过构造函数访问static型数据ibookNumber并使其自增1 9 ~Book() { ibookNumber--; } //对象在被撤销时将static型数据ibookNumber并使其自减110 void showNum() { cout<<"Book number = "<<ibookNumber<<endl; }11 private:12 static int ibookNumber; //static类型数据成员 ibookNumber13 };14 15 int Book::ibookNumber = 0; //在类外对static类型的数据成员进行初始化16 17 int main()18 {19 Book A; Book B; Book C; Book D; Book E; //创建一些对象20 A.showNum(); //使用对象A查看当前对象个数21 B.showNum(); //使用对象B查看当前对象个数22 cout<<"销毁一些对象...\n";23 B.~Book(); C.~Book(); //将B、C对象进行撤销24 D.showNum(); //使用D对象查看剩余对象个数25 E.showNum(); //使用E对象查看剩余对象个数26 27 return 0;28 }
编译运行的结果:
Book number = 5 Book number = 5 销毁一些对象... Book number = 3 Book number = 3 Process returned 0 (0x0) execution time : 0.266 s Press any key to continue.
代码说明:
在上面代码的类Book中, 我们声明了一个 static 类型的ibookNumber 作为创建多少对象的统计变量, Book的构造函数的作用是当对象创建时将 ibookNumber 的值自增1, 而析构函数的则负责将 ibookNumber 自减1。
main函数中, 创建了 A-E共5个对象, 在创建完成后, 通过 A 对象输出对象的总数和 B 对象输出的结果是相同的, 都是5个, 然后销毁 B、C 对象, 用D、E对象查看剩余对象个数, 结果都为3, 可以看出, static型的数据成员任何对象都可以进行访问, 并且在创建后所产生的实例是唯一的。
附注:
一般我们进行成员变量初始化用两种方法
第一种是通过在构造函数内赋值
class Point
{
public:
Point(){ _x = 0; _y = 0;};
Point( int x, int y ){ _x = 0; _y = 0; }
private:
int _x, _y;
};
第二种是使用初始化列表
class Point
{
public:
Point():_x(0),_y(0){};
Point( int x, int y ):_x(x),_y(y){}
private:
int _x, _y;
};
这两种用法是有区别的
一、在有些情况下,必须使用初始化列表。特别是const和引用数据成员被初始化时。
class Point
{
// 这个类的定义就要求使用初始化成员列表,因为const成员只能被初始化,不能被赋值
public:
Point():_x(0),_y(0){};
Point( int x, int y ):_x(x),_y(y){}
//Point(){ _x = 0; _y = 0;}
//Point( int x, int y ){ _x = 0; _y = 0; }
private:
const int _x, _y;
};
二、是从效率方面来说的,对于内置类型或复合类型,差异不会太大,但对于非内置数据类型,差异还是很明显的
如我们再给Point类添加一个新的string类型的成员变量
class Point
{
const int _x, _y;
string _name;
};
构造函数内赋值进行初始化
Point( int x, int y, string name ){ _x = 0; _y = 0; _name = name; }
_name = name 这个表达式会调用string类的缺省构造函数一次,再调用Operator=函数进行赋值一次。所以需调用两次函数:一次构造,一次赋值
用初始化列表进行初始化
Point( int x, int y, string name ):_x(x),_y(y), _name(name){}
_name会通过拷贝构造函数仅以一个函数调用的代码完成初始化
即使是一个很简单的string类型,不必要的函数调用也会造成很高的代价。随着类越来越大,越来越复杂,它们的构造函数也越来越大而复杂,那么对象创建的代价也越来越高,所以一般情况下建议使用初始化列表进行初始化,不但可以满足const和引用成员的初始化要求,还可以避免低效的初始化数据成员。
- 【学习C++】学习C++ -> 类的特殊数据成员
- 学习C++ -> 类的特殊数据成员
- 学习C++——几个特殊的成员函数
- C++Primer学习笔记103 特殊工具与技术 类成员指针
- C++:特殊成员函数
- 类的特殊数据成员
- C/C++学习笔记:指向类成员变量的指针
- Object-C学习——类的静态成员
- 一步一步学习C++(类)之成员函数的特性
- C++学习-特殊成员
- 【C++】类的静态数据成员
- Objective-C类的静态数据成员
- C++—特殊成员函数
- 学习objective-c的一些特殊的地方
- C语言的基础学习及特殊例题的实现
- 【从C到C++学习笔记】类声明/公有私有保护成员/数据抽象和封装
- C++类的特殊数据成员
- C++类的特殊数据成员
- c语言入门学习归纳(第1部分)
- Field Guide to Hadoop.pdf 英文原版 免费下载
- ActiveMQ 02 JMS规范
- Ubuntu修改系统的默认启动级别
- django-7-Git
- 【学习C++】学习C++ -> 类的特殊数据成员
- Hadoop The Definitive Guide, 4th Edition.pdf 英文原版 mfxz
- Vue.js 入门
- matplotlib命令与格式:坐标轴数值格式(日期格式,百分比,科学记数)
- 史上最全设计模式导学
- 给 Java 开发者的 10 个大数据工具和框架
- 第4章 控制执行流程
- ActiveMQ 03 ActiveMQ基础
- 【Scikit-Learn 中文文档】半监督学习