基础议题
1.仔细区别pointers和references
2.最好使用c++转型操作符
3.绝对不要以多台方式处理数组
4.非必要补提供default construnctors
1仔细区别pointers和references
指针:这玩意相信大家都不陌生了.(万恶之源).
引用:这是我在学了C++之后新接触的东西,乍看很高端,其实底层的实现也就是一个指针.(vs2013底层汇编是以常指针的形式实现的)
在c++中,引用又分为左值引用和右值引用.这些都是后话
相关笔记:
1.引用相关注意点:
1.引用必须初始化
2.没有所谓的空引用
3.引用在定义时,知识吧某个变量的地址和这个引用变量绑定到一起,而不是完全拷贝
4.不能定义引用的引用
5.引用智能绑定对象和变量,不能绑定字面值和计算结果.
6.引用不是对象,所以没有实际的地址
引用和指针的区别
- 引用在定义时必须初始化,指针没有要求
- 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
- 没有NULL引用,但有NULL指针
- 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
- 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
- 有多级指针,但是没有多级引用
- 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
- 引用比指针使用起来相对更安全
2最好使用C++转型操作符
转型操作符:
1.static_cast:
用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换
只要不涉及继承机制,一般的变量都可以使用这个
2.const_cast:
const_cast最常用的用途就是删除变量的const属性,方便赋值
3.dynamic_cast:
用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则) 向下转型:父类对象指针/引用- >子类指针/引用(用dynamic_cast转型是安全的)
注意
- dynamic_cast只能用于含有虚函数的类
- dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
4.reinterpret_cast
reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型
也就是说,我们可以使用reinterpret_cast来强迫了解我们的意图!!!但是,因为reinterpre_cast是直接操作位模式的,所以,在移植性上有很大的不便
通过宏来自定义类型转换
#define static_cast (type,expr) ((type)(expr))
#define const_cast(type,expr) ((type)(expr))
#define reinterpret_cast (type,expr) ((type)(expr))
3绝对不要以多态的方式处理数组
1.假设有一个类BST(binary rearch tree),以及一个继承自BST的类BalanceBST;
2.现在考虑下面一个函数,用来打印BSTs数组中的每一个BST的内容:
void printBSTArray(ostream& s, const BST array[], int numElements)
{
for (int i = 0; i < numElements; i++)
{
s << array[i];
}
}
如果将BST对象组成的数组传给此函数
BST BSTArray[10];
printBSTArray(cout,BSTArray,10);
但是如果如果将BalanceBST对象组成的数组交给这个函数
BalanceBST bBSTArray[10];
printBSTArray(cout,bBSTArray,10);
会发成未知的行为。
因为第一BST对象和BalanceBST对象所占内存大小是不一样的,理论上派生类会比基类所占的内存要大一点;第二array是一个指针,array[i]相当于*(array+i),array和array+i在内存上相距多远?答案是i*sizeof(BST),因为理论上BST数组全是BST类型的对象。所以当派生类对象传进去的时候,sizeof(BST)和sizeof(BalanceBST)在内存上不一定能对应,这个结果是不可预期的。
同理,如果尝试通过一个base class指针,删除一个有derived class objects组成的数组,上述问题也会出现,这也是为什么析构函数为虚函数的原因。
4非必要不提供default constructor
关于默认构造:
1.当没有任何显示构造函数时,编译器会自动"赠送"我们一个默认的构造函数;
当我们不提供默认构造函数时:
1.无法产生数组;
class Equipments {
public:
Equipments( int ID ); //使编译器无法合成default constructor
……
};
Equipments bestPieces[10]; // error! 数组的基本元素对象无法生成
Equipments *bestPieces = new Equipments[10] // error!同理
找到一篇较好的博客,可以查看这个
https://www.dazhuanlan.com/2019/09/27/5d8d44a5f2862/