C++不是一个带有一组守则的一体语言;它是从四个次语言组成的联邦政府,每个次语言都有自己的规约
encapsulation
),继承(inheritance
)、多态(polymorphism
)、virtual函数(动态绑定)containers
)、迭代器(iterators
)、算法(algorithms
)以及函数对象(function objects
)#define
定义的常量可能不会被编译器看到,也有可能没有进入记号表(symbol table)内
而解决方法是以一个常量替换上述的宏(#define
):
const double AspectRatio = 1.6534; //大写名称通常用于宏
记住:
const
对象或 enums
替换 #defines
inline
函数替换 #defines
const
允许你指定一个语义约束。其可以在 classes
外部修饰 global
或 namespace
作用域中被声明为 static
的对象。你也可以用它修饰 classes
内部的 static
和 non-static
成员变量。面对指针,你也可以指出指针自身、指针所指物,或两者都(或都不)是const
char greeting[] = "Hello";
char *p = greeting; // non-const pointer, non-const data
const char* p = greeting; // non-const pointer, const data
char* const p = greeting; // const pointer, non-const data
const char* const p = greeting; // const pointer, const data
记忆:如果关键字const
出现在星号左边,表示被指物是常量;如果出现在星号右边,表示指针自身是常量;如果出现在星号两边,表示被指物和指针两者都是常量
STL迭代器作用像个T*
指针。声明迭代器为 const
一样,表示这个迭代器不得不指向不同的东西,但它所指的东西的指是可以改动的。如果希望其所指的东西不可悲改动(即希望STL模拟一个const T*指针),则需要的是const_iterator
std::vector vec;
const std::vector::iterator iter = vec.begin(); //iter的作用像个T* cosnt
*iter = 10; //没有问题,改变iter所指物
++iter; //错误,iter是const
std::vector::const_iterator cIter = vec.begin(); //citer的作用像个const T*
*cIter = 10; //错误,*cIter是const
++cIter; //没问题
永远在使用对象之前先将其初始化,对内置型对象进行手工初始化,因为C++不保证初始化它们。对于内置类型以外的其他东西,初始化责任落在构造函数身上。规则很简单:确保每一个构造函数都将对象的每一个成员初始化。
赋值和初始化容易弄错:
//赋值版本
class A {
public: A(const std::string& name, const std::string& address);
private:
std::string theName;
std::string theAddress;
}
A:A(const std::string& name, const std::string& address) {
theName = name; //这些都是赋值,不是初始化
theAddress = address;
}
//初始化版本
class A {
public: A(const std::string& name, const std::string& address);
private:
std::string theName;
std::string theAddress;
}
A:A(const std::string& name, const std::string& address):theName(name), theAddress(address) {
}
基于赋值的版本,首先调用default构造函数为theName,theAddress设初值,然后立刻对其赋予新值。
总结:
const
或references
,他们就一定需要初值,不能被赋值。member initialization list
),而不要在构造函数本体内使用赋值操作。初值列列出的成员变量,其排列次序应该和它们在class中的声明次序相同