Introduction
模版声明
template<class T>
class SmartPointer; // template declaration
模版定义
template<class T>
class SmartPointer
{ // template definition
public:
SmartPointer(T *p = 0);
~SmartPointer();
T * operator->() const;
T& operator*() const;
...
};
定义一个数组和指针数组的细微的区别:定义数组时调用类构造函数,
class A {
public:
A(); // default constructor
};
A arrayA[10]; // 10 constructors called
class B {
public:
B(int x = 0); // default constructor
};
B arrayB[10]; // 10 constructors called,
// each with an arg of 0
class C {
public:
C(int x); // not a default constructor
};
C arrayC[10]; // error!
定义指针数组时不调用:
C *ptrArray[10]; // no constructors called
ptrArray[0] = new C(22); // allocate and construct
// 1 C object
ptrArray[1] = new C(4); // ditto
通常在定义一个类的时候定义一个拷贝构造函数
class String {
public:
String(); // default constructor
String(const String& rhs); // copy constructor
...
private:
char *data;
};
String s1; // call default constructor
String s2(s1); // call copy constructor
String s3 = s2; // call copy constructor
定义操作符+,
const String operator+(String s1, String s2)
{
String temp;
delete [] temp.data;
temp.data =
new char[strlen(s1.data) + strlen(s2.data) + 1];
strcpy(temp.data, s1.data);
strcat(temp.data, s2.data);
return temp;
}
String a("Hello");
String b(" world");
String c = a + b; // c = String("Hello world")
在这个函数中调用拷贝构造函数的次数请参考Item19。在编程中,当想用字符类型时,应该尽量使用标准库中的string而不是String或CString,String是string在C++中的扩展(为安全起见你可以自己写一个字符串类)。至于char*s这样的字符串尽量少用。参考Item49,Item M29,30。
下一个问题是区别”初始化(initialization)”和”赋值(assignment)”。初始化是指对象是指第一次给定一个值,而赋值是已经初始化的对象改变他的值。前者调用拷贝构造函数,后者调用=操作符。
string s1; // initialization
string s2("Hello"); // initialization
string s3 = s2; // initialization
s1 = s3; // assignment
从纯粹的函数调用来说,调用拷贝构造函数需要考虑参数的有效性,而操作函数的参数一般是合法的,因为已经经过调用构造函数了。但是另一面,操作函数的目标对象,一般已经分配了资源(内存),在新的值赋予之前,要先释放资源。
以下是一个自定义String类拷贝构造函数和=操作符的例子:
// a possible String constructor
String::String(const char *value)
{
if (value) { // if value ptr isn't null
data = new char[strlen(value) + 1];
strcpy(data,value);
}
else { // handle null value ptr3
data = new char[1];
*data = '/0'; // add trailing null char
}
}
// a possible String assignment operator
String& String::operator=(const String& rhs)
{
if (this == &rhs)
return *this; // concentrates on detecting pathological conditions, such as //assignment to itself. see Item 17
delete [] data; // delete old memory
data = // allocate new memory
new char[strlen(rhs.data) + 1];
strcpy(data, rhs.data);
return *this; // see Item 15
}
关于bool类型的定义,可自定义如下
typedef int bool;
const bool false = 0;
const bool true = 1;
关于强制类型转换
static_cast<type>(expression) // cast expression to be of “type” type
const_cast<type>(expression)
dynamic_cast<type>(expression) <type>
reinterpret_cast<type>(expression) <type>
区别和用途如下:
const_cast为了去除对象和指针的const属性而转换 Item21
dynamic_case为了安全转换Item39
reinterpret_cast为了转换独立实现的结果(casts that yield implementation-dependent results),比如强制转换函数指针。不常用。
static_cast是其他类型不能用时采用的转换类型。从意义上讲更接近于C类型的转换。
考虑到类型检测和错误诊断,推荐使用这些新类型的强制转换而不用传统的C类型的强制转换(就是(type) expression ),
关于本书例子程序用语的说明,指针的命名
string *ps; // ps = ptr to string
class Airplane;
Airplane *pa; // pa = ptr to Airplane
class BankAccount;
BankAccount *pba; // pba = ptr to BankAccount