- monolake 的GeekBand C++开发学习笔记(五)
- monolake 的GeekBand C++开发学习笔记(六)
- monolake 的GeekBand C++开发学习笔记(七)
- monolake 的GeekBand C++开发学习笔记(九)
- monolake 的GeekBand C++开发学习笔记(八)
- monolake 的GeekBand C++开发学习笔记(十)
- monolake 的GeekBand C++开发学习笔记(十一)
- monolake 的GeekBand C++开发学习笔记(十二)
- monolake 的GeekBand C++开发学习笔记(十四)
- monolake 的GeekBand C++开发学习笔记(十三)
前记:进入面向对象编程(下)的课程的第二周,也是最后一周。本周课程主要从类的内存模型入手,讲解类对象内存的构成,虚函数指针vptr,虚函数表vtbl。以及虚函数构成的动态联编(dynamic binding),const的注意事项。引申重点讲解了operator new和operator delete的重载,以及如何拓展basic_string的容量大小。就本周学习内容,我记录以下心得。
size_t类型
在operator new重载里经常出现size_t类型。什么是size_t呢?size_t其实就是unsigned int的一种表示别名(在64系统中为long unsigned int),它定义在cstddef头文件中。使用它的目的是提供一种可移植的方法来声明与系统中可寻址的内存区域一致的长度。简单的理解就是:让我们一目了然就知道,这个类型的变量就是指的是占用内存地址长度或者相关的值。一个实例就是sizeof操作符结果类型是size_t,sizeof得出的是占用内存的长度,且size_t单位长度与系统有关,32位系统为4字节,64位系统中为8字节(这样的长度关系契合与不同系统中的地址位数)。因此使用size_t类型名移植性更好,当然可读性也更强。
另外size_t也一般可以用来存储指针,这个很好理解,因为指针就是指向地址的,用size_t类型表达无可厚非。在C++中使用sizeof(ptr)指示出指针长度。参考内容[1]。
列表初始化
在侯老师课中以及李老师的习题讲解中都多次提到尽量使用“成员列表初始化”。避免使用函数本里内的赋值。
首先明白以下两点(参考资料:effective c++):
(1)在C++中的构造函数做两个工作:1,成员初始化;2,成员赋值。
(2)对象成员变量的初始化动作在进入函数本里之前进行。
如果在函数本体内赋值,相当于先将成员变量进行初始化再进行赋值。如果是内置类型则无关紧要,但是如果成员是类对象的话,就要进行以下动作:调用成员对象所属class的default构造函数,然后对它进行赋值操作。如果使用列表初始化成员对象,就是直接调用成员所属class的copy 构造函数。效率上高很多。
验证程序如下:
#include <iostream>
using namespace std;
class A
{
int x;
public:
A() { cout << "A default ctor.\n"; };
A(int _x) :x(_x) { cout << "A ctor.\n"; };
A(A& a) :x(a.x) { cout << "A copy ctor.\n"; };
void operator =(A& a) { x = a.x;cout << "operator = assigned.\n"; };
};
class B
{
int y;
A a;
public:
B() { cout << "B default ctor.\n"; };
B(A& _a, int _y) :a(_a), y(_y) { cout << "B initialization ctor.\n"; }; //采用列表初始化
B(A& _a, int _y) { a = _a; y = y;cout << "B assigned ctor.\n"; }; //采用函数本体赋值
B(B& b) :a(b.a), y(b.y) { cout << "B copy ctor.\n"; };
};
int main()
{
cout << "create a A objector:\n";
A a(1);
cout << "create a B objector:\n";
B b(a,2);
cin.get();
return 0;
}
采用列表初始化方法得出的结果:
initialization1.PNG可以看出采用列表初始化创建B时,是调用了A的copy 构造函数。
采用构造函数本体内赋值方法的结果:
assigned1.PNG可以看出来构造函数本体内赋值生成B时,先调用default构造函数,然后在operator =进行赋值操作。
所以说尽量采用成员列表初始化进行构造函数。
PS:如果有成员没有参数或不想它进行初始化,怎么办呢?可已将成员列表初始化的()内容空着,进行无参数(noting)初始化,例如以下用法:
B(int _y):a(),y(_y) {};
但是尽量对内置类型进行参数初始化,因为就像我笔记(三)里提到的,未初始化的内置变量的值是不确定的。
网友评论