1. 当代软件架构实践中的经验

(1)尽量使用单重继承的方式进行系统设计

(2)尽量保持系统中只存在单一的继承树

(3)尽量使用组合关系代替继承关系

2. 不幸的事实

(1)C++语言的灵活性使得代码中可以存在多个继承树

(2)C++编译器的差异使得同样的代码可能表现不同的行为(如new操作结果失败,有的编译器会返回NULL,有的会抛std::bad_alloc异常)

3. 创建DTLib::Object类的意义

(1)遵循经典设计准则,所有数据结构都继承自Object类

(2)定义动态内存申请的行为,提高代码的移植性(即重载operator new,让new的失败时在不同的编译器下都能返回NULL,而不是抛出异常或返回NULL等多种结果)

【编程实验】顶层父类的创建

//Object.h

#ifndef _OBJECT_H_
#define _OBJECT_H_

namespace DTLib
{

class Object
{
public:
    //以下四个重载函数用于统一不同编译器new失败时的结果不同的问题。
    //throw()表示不抛出异常,即如果申请内请失败时,统一返回NULL而不抛异常
    void* operator new(unsigned int size) throw();
    void operator delete(void* p);
    void* operator new[](unsigned int size) throw();
    void operator delete[](void* p);

    virtual ~Object() = 0;
};

}


#endif // _OBJECT_H_

//Object.cpp

#include "Object.h"
#include <cstdlib>
#include <iostream>

using namespace std;

namespace DTLib {

void * Object::operator new(unsigned int size)  throw()
{
    cout <<"Object::operator new: " << size << endl;
    return malloc(size);
}

void Object::operator delete(void *p)
{
    cout <<"Object::operator delete: " << p << endl;
    free(p);
}

void *Object::operator new[](unsigned int size) throw()
{
    //当用new Test[5]时,只须传入数组元素的个数,编译器会向operator new[](...)函数的参数
    //传入5*sizeof(Test) + sizeof(unsigned int),其中的sizeof(unsigned int)为额外
    //空间,用于保存元素的个数。
    cout <<"Object::operator new[]: " << size << endl;
    return malloc(size);
}

void Object::operator delete[](void *p)
{
    cout <<"Object::operator delete[]: " << p << endl;
    free(p);
}

Object::~Object()
{

}


}

//main.cpp

#include <iostream>
#include "Object.h"
using namespace std;
using namespace DTLib;

class Test : public Object
{
public:
    int i;
    int j;
};

class Child : public Test
{
public:
    int k;
};

int main()
{
    Object* obj1 = new Test();
    Object* obj2 = new Child();

    cout << "obj1 = " << obj1 << endl;
    cout << "obj2 = " << obj2 << endl;

    delete obj1;
    delete obj2;

    return 0;
}
/*输出结果
Object::operator new: 12
Object::operator new: 16
obj1 = 0x3d12a8
obj2 = 0x3d12c0
Object::operator delete: 0x3d12a8
Object::operator delete: 0x3d12c0
*/

4. 小结

(1)Object是DTLib中数据结构类的顶层父类

(2)Object类用于统一动态内存申请的行为

(3)在堆中创建Object子类的对象,失败时返回NULL值

(4)Object类为纯虚父类,所有子类都能进行动态类型识别。