More Effiective C++(1) 无默认构造函数
在看More Effective C++的基础上,总结出一些需要注意的点
1.区别pointer与reference
reference
一定会指向对象,不能指向空,指向不会变
pointer
可能指向空对象,null
,指向的对象可以变化
reference
使用时不用测试其有效性,因为它不可能指向null/当指向内容不变,或返回值要当左值时,需使用引用。 note:不能返回临时变量的引用
其他时候,使用pointer
2.类型转换:
static_cast<type>
:
dynamic_cast<type>
:多态父类与子类之间转换,一般用于将指向子类的父类指针或饮用强转换为子类指针或引用
若父类初始化是不指向该子类,则强转失败,会返回null
如果 downcast 是安全的(也就说,如果基类指针或者引用确实指向一个派生类对象)这个运算符会传回适当转型过的指针。
如果 downcast 不安全,这个运算符会传回空指针(也就是说,基类指针或者引用没有指向一个派生类对象)
const_cast<type>
:去常量转换
reinterpret_cast<type>
:与编译器相关,不具有移植性,最常用于转换“函数指针”类型
3.多态与数组不要混用
//不要用多态处理数组,数组使用指针的形式表述的*(a + i),而子类和父类的大小一般不同
//多态和指针算术不能混用
4.没有default constructor初始化数组
若对象没有默认构造函数,则在创建数组时会出现一些问题
class A {
public:
A(int a) : _a(a) {
cout << a << endl
}
~A(){}
private:
int _a;
};
A arrayA[10];//error no matching constructor
A *pA = new A[10];//error no matching constructor
有三种方法可以解决该问题
方法1
使用non-heap数组
A arrayA[3] = {A(1), A(2), A(3)};
方法2
使用指针数组
A *pA[3];
A *pA = new A[3];
然后通过循环赋值
缺点:占用内存较大,并且要将数组指向的所有对象删除,不然会导致内存泄漏
方法3
使用raw memory,可以避免过度使用内存,然后用placement new 在其之上构造对象
//创建raw memory
void *rawMemory = operator new[](10 * sizeof(A));
//让pA指向这块内存,可以看作一个A数组
A *pA = static_cast<A*>rawMemory;
//利用placement new创建对象
for (int i = 0; i < 10; ++i) {
new (&pA[i])A(i);
}
//此时需要自己调用析构函数
for (int i = 0; i < 10; ++i) {
pA[i].~A();
}
//释放raw memory
operator delete[] (rawMemory);
结论
1.没有默认构造函数的将不适用于模板基类编程
2.虚基类应该有默认构造函数
#include <iostream>
using namespace std;
class A {//实现多态,需要有虚函数,继承,父类指针指向子类对象
// 多态:同一操作作用于不同对象,可以有不同的解释,产生不同的执行效果,可通过指向父类的指针调用子类中的方法
// 把不同的子类都当作父类来看,屏蔽不同子类之间的差异,写出通用的代码,做出通用的编程
// 父类型的引用就可以根据当前赋值给它的子对象的特性以不同的方式运作
public:
virtual void x(){}
};
class B : public A {
public:
B() {
cout << "BBB" << endl;
}
};
void update(B *pB) {}
void update2(B &rB) {}
void printInt(const int &ri) {
cout << ri << endl;
}
void printInt(const int *pi) {//指针的话要判断
if (pi) {
cout << *pi << endl;
}
}
class C {};
void testCast() {
A *pA = new A;// pA不指向B
// update(pA); //invalid conversion from 'A' to 'B'
try {
B pB = dynamic_cast<B>(pA);//强转时指向空指针
if (pB == NULL) {
cout << "cast error!\n";//因为此时pA指向的对象是A,不能强转为B
}
update(pB);
update2(dynamic_cast<B&>(*pA));//发生异常
}
catch (exception &e) {
cout << " hello" <<endl;
}
pA = new B;
B *pB = dynamic_cast<B*>(pA);
update(pB);
return ;
}
int main() {
int a = 0;
// int &b; //error: 'b' declared as reference but not initialized
printInt(a);
printInt(&a);
testCast();
return 0;
}