effective35_基础议题

基础议题

1.仔细区别pointers和references
2.最好使用c++转型操作符
3.绝对不要以多台方式处理数组
4.非必要补提供default construnctors

1仔细区别pointers和references

指针:这玩意相信大家都不陌生了.(万恶之源).

引用:这是我在学了C++之后新接触的东西,乍看很高端,其实底层的实现也就是一个指针.(vs2013底层汇编是以常指针的形式实现的)

在c++中,引用又分为左值引用和右值引用.这些都是后话

相关笔记:

1.引用相关注意点:

1.引用必须初始化
2.没有所谓的空引用
3.引用在定义时,知识吧某个变量的地址和这个引用变量绑定到一起,而不是完全拷贝
4.不能定义引用的引用
5.引用智能绑定对象和变量,不能绑定字面值和计算结果.
6.引用不是对象,所以没有实际的地址

引用和指针的区别
  1. 引用在定义时必须初始化,指针没有要求
  2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
  3. 没有NULL引用,但有NULL指针
  4. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
  5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  6. 有多级指针,但是没有多级引用
  7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  8. 引用比指针使用起来相对更安全

2最好使用C++转型操作符

转型操作符:
1.static_cast:

用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换
只要不涉及继承机制,一般的变量都可以使用这个

2.const_cast:

const_cast最常用的用途就是删除变量的const属性,方便赋值

3.dynamic_cast:

用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)

  向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
  
  向下转型:父类对象指针/引用- >子类指针/引用(用dynamic_cast转型是安全的)

注意

  1. dynamic_cast只能用于含有虚函数的类
  2. 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/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值