把C++看作一个语言联邦。
嗯…….
作者在书中提的原因非常简单,#define 定义的宏不利于debug。
例如#define DOG 5
,经过了预处理,程序不知道DOG的存在,他只知道有个数字5,如果在这报错,错误提示课可能会提到5,但肯定不会出现DOG,定位错误非常麻烦。
用const来代替是一个好方法,如上则可以换成const int dog = 5;
(用constexpr肯定也行。
对需要把常量局限于类中时可以用static int dog = 5;
。
当然对于某些编译器在声明式上获取初值不被允许(就是你vc6),而你在编译期间又不得不需要这样一个常数,那可以使用enum hack。
class cls{
private:
enum{ dog = 5 };
int dogs[dog]
};
对于用宏来定义函数,你完全可以用模版內联函数来代替。
template<typename T>
inline T MAX(const T& a,const T& b){
return (a > b) ? a:b;
}
而宏定义的函数虽然可以达到同样的效果,但是会发生奇奇怪怪的事。。(例子略…..
首先是很多时候都搞不清楚的指针常量和常量指针。举几个例子
int a =5;
int *b =new int(5);
const int c = 5;
const int* d = new int(5);//数据不能改变
int *const e = new int(5);//指针的指向不能变
const int *const f= new int(5);//指针指向和数据都不能变
看起来很难,但是有个简单的记忆方法,就是看const离谁近。
比如const int* a
,const靠近int,这代表数据不能改,意味着*a = 3;//Error!
。
int *const d
. 这个const和*挨得近,代表着指针指向改不了,d = &c;//Error!
。
当然还有种写法int const*
,它与const int*
等同。
如果出现了两个const,毫无疑问,什么也改不了。
对于STL的迭代器,它就像个T*
指针,如果希望它的指向不变,只要声明一个const的迭代器(T* const
),如果希望它指的东西的值不变,则需要一个从const_iterator(const T*
)
std::vector<int> vec;
……………
const std::vector<int>::iterator tier = vec.begin();
*iter = 10;//ok!
++iter;//error!
std::vector<int>::const_iterator cIter = vec.begin();
*cIter = 10;//error!
++cIter; //ok!
让函数的返回值为const也可以避免些奇奇怪怪的错误,例如一个返回const的重载操作符 * 可以避免这样的错误(a * b) = c;//error!
。
另一个点是,对于non-const的成员函数,可以重载构建一个const的成员函数。
class cls{
public:
cls operator+(cls b); //for non-const object
cls operator+(cls b)const;//for const object
};
如果有这样一个常量的cls对象调用“+”号,那么它用的是那个const的操作符重载,而non-const的对象相反。
如果一个成员函数是const的,那它在函数内就不能改变类中的任何属性。如果你想改变其中某个属性,请把它声明为mutable。
c++存在无初值对象,而没有初值(未初始化)会导致坏事发生。 所以一定要保重值的初始化。 在class中尽量使用成员初值列来进行初始化,因为c++规定成员的变量初始化发生在其进入构造函数之前。
class Integer{
Public:int a,b;
Integer():a(0)//这才是真正的初始化
{
b = 0;//这叫赋值,不是初始化
}
}
最好把所有成员放入初值列中,以防遗漏,而且尽量按照声明顺序去列初值列,以免遇到奇怪的错误。 当遇到定义在不同编译单元的不同对象,初始化的顺序难以决定,这时可以使用local-static const代替static const,就是定义一个返回值为local static对象引用的函数。比如
obj& getObj()
{
static obj object;
return object;
}
这样就能确定目标一定被初始化了。
这个是真的不看不知道,一看吓一跳,原来那些我认为理所当然的操作都是编译器默默努力的结果。
首先,编译器会自动创建默认的构造函数和构析函数,其次,还会创建copy构造函数和copy assignment操作符。比如我有一个空类cls,但是有些操作我是一定能执行的,举例如下:
class cls{};
cls a,b; //default constructor
cls c(a); //copy constructor
a = b; //copy assignment
//destructor
但是
如果你想拥有一个独一无二的类:不让它被复制一份,那么可以做如下的方法: