抽象数据类型
设计一个好程序库的要求之一就是彻底隔离接口和实现,C++的做法是通过构造、析构函数和成员函数:
- C++语言中将接口和实现分隔开的基本的方法之一就是采用构造函数和析构函数。构造函数本身提供了生成给定类对象的方法;析构函数则提供了与构造函数想法的行为。
- 成员函数能够防止用户访问那些他们不应该看到的类成员。
类型安全地链接
使用C库时,可能一个函数存在于多个库内,例如sqrt(double)可能在math.h头文件内,
extern double sqrt(double);
sqrt(Complex)在复数库文件Complex.h内,
extern Complex sqrt(Complex);
此时,可以用这种声明语法解决:
extern "C" double sqrt(double);
extern "C" Complex sqrt(Complex);
extern "C"这种处理的确切含义取决于特定系统处理C函数的具体方式。
命名空间
命名空间解决了一种在C中十分突出而在C++愈加严重的问题:如何防止在不同的程序库设计者为各自组件采用同样的名字。
本质上命名空间允许库设计者对会被库方到全局作用域的所有名称指定一个包装器,它的两种使用方法:
例如ShadowSoft公司的库命名空间名为ShadowSoft,其中定义的String s,一种用法是通过使用命名空间标识的名字:
Shadow::String s;
一种是引用命名空间:
using namespace ShadowSoft;
String s;
内存分配
这部分讲了一个看似冲突的内存分配案例:
public:
void*operatornew (size_t);
void*operator delete(void*);
};
这个类自己定义了一套内存管理的方案(new、delete),现在,无论何时想在内存中建立或释放一个Foo对象,都得通过Foo::operator new和Foo::operator delete来动态分配内存。如果我们通过系统内存分配函数申请内存,再在此内存中建立Foo对象会怎样呢?例如这样:
Foo* tp =new (p) Foo;
答案是容器时具有优先权的,new(p) Foo将由p定址的内存中分配一个Foo对象,即使类Foo有自己的内存分配器。
按成员赋值和初始化
对于结构体的赋值,如果结构体成员里有复杂类型的成员,例如是一个类,我们不清楚该类的赋值过程是按位复制或是其他方法,我们可以显示的构造和复制。
{
string name;
string address;
string telno;
Person();
Person (const Person& p):name(p.name),address(p.address),telno(p.telno) {}
Person operator=(const Person& p)
{
name = p.name;
address = p.address;
telno = p.telno;
return*this;
}
};
注意:没有必要给Person类一个显示的析构函数,因为编译器会正确的从string类的析构函数中继承析构函数。