1. 程式人生 > >Cpp數據結構實戰開發2-基本類的構建

Cpp數據結構實戰開發2-基本類的構建

isnull 頭文件 原則 get() 對象創建 sage 機制 重載操作符 else

  • 構建自己的類庫,MxLib
    叠代開發
    單一繼承樹:所有類繼承自Object類,規範堆對象創建時的行為
    只拋異常,不處理:使用宏拋出異常,提高可移植性
    弱耦合性:盡量不使用標準庫中的類和函數,提高可移植性

頂層父類

  • 軟件架構實踐經驗:
    盡量使用單重繼承的方式進行系統設計
    盡量保持系統中只存在單一的繼承樹
    盡量使用組合關系代替繼承關系

在MxLib中創建Objec類,所有類都繼承自MxLib::Object類,統一定義動態內存申請和銷毀的行為

頭文件 Object.h

#ifndef OBJECT_H
#define OBJECT_H

namespace MxLib
{

class Object
{

public
: /** * 以下通過重載操作符的方式統一定義動態內存申請和銷毀的行為,提高代碼的可移植性 */ 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.cpp

#include "Object.h"
#include <cstdlib> // 可以根據實際的需要更換頭文件 namespace MxLib { void* Object::operator new(unsigned int size) throw() // 申請內存失敗不會拋異常,返回 NULL { return malloc(size); } void Object::operator delete(void* p) { free(p); } void* Object::operator new[](unsigned int size) throw() // 申請內存失敗不會拋異常,返回 NULL
{ return malloc(size); } void Object::operator delete[](void* p) { free(p); } // 父類的析構函數即使是純虛函數也要提供實現 Object::~Object(){} }

智能指針

  • 使用目的
    智能指針最大程度上避免堆空間內存泄露問題
  • 特點
    指針生命周期結束時主動釋放堆空間
    智能指針只能用於指向堆空間中的內存
    重載指針特征符(-> 和 *)能夠使用對象代替指針
    最多由一個指針標識指向一片堆空間
  • 註意
    杜絕指針指針的運算和比較
    智能指針智能用來指向堆空間的單個對象或變量

頭文件 SmartPointer.h

#ifndef SMARTPOINTER_H
#define SMARTPOINTER_H

#include "Object.h"

namespace MxLib
{

template <typename T>
class SmartPointer : public Object
{
protected:
    T* pointer;

public:
    SmartPointer(T* pointer = NULL)
    {
        this->pointer = pointer;
    }

    /**
     * 在拷貝構造函數和重載賦值操作符中,使一個指針標識最多指向一片堆空間
     */
    SmartPointer(const SmartPointer<T>& obj)
    {
        this->pointer = obj.pointer;
        const_cast<SmartPointer<T>&>(obj).pointer = NULL;
    }

    SmartPointer<T>& operator = (const SmartPointer<T>& obj)
    {
        if (this != &obj)
        {
            delete this->pointer;
            this->pointer = obj.pointer;
            const_cast<SmartPointer<T>&>(obj).pointer = NULL;
        }
        return *this;
    }

    /**
     * 重載指針特征符(-> 和 *)能夠使用對象代替指針
     */
    T* operator -> ()
    {
        return this->pointer;
    }

    T& operator * ()
    {
        return *(this->pointer);
    }

    bool isNull() {
        return (this->pointer == NULL);
    }

    T* get() {
        return this->pointer;
    }

    ~SmartPointer() // 只能用來指向堆空間中的單個變量或對象
    {
        delete this->pointer;
    }
};
}

#endif // SMARTPOINTER_H

異常類

使用異常機制能分離代碼的正常邏輯和異常邏輯
類類型異常的匹配依舊是至上而下嚴格匹配,符合賦值兼容性原則
一般匹配子類異常的catch放在上部;匹配父類的放下部

頭文件 Exception.h

#ifndef EXCEPTION_H
#define EXCEPTION_H

#include "Object.h"

namespace MxLib
{
// 使用宏簡化代碼
#define THROW_EXCEPTION(e, m) (throw e(m, __FILE__, __LINE__))

class Exception : public Object
{
protected:
    char* message;
    char* location;

    void init(const char* message, const char* file, int line);
public:
    Exception(const char* message);
    Exception(const char* file, int line);
    Exception(const char* message, const char* file, int line);

    Exception(const Exception& e);
    Exception& operator = (const Exception& e);

    virtual const char* getMessage() const;
    virtual const char* getLocation() const;

    // 父類的析構函數即使是純虛函數也要提供實現
    virtual ~Exception() = 0;
};

/**
計算異常
*/
class ArithmeticException : public Exception
{
public:
    ArithmeticException() : Exception(0) {}
    ArithmeticException(const char* message) : Exception(message) {}
    ArithmeticException(const char* file, int line) : Exception(file, line) {}
    ArithmeticException(const char* message, const char* file, int line) : Exception(message, file, line) {}

    ArithmeticException(const ArithmeticException& e) : Exception(e) {}

    ArithmeticException& operator = (const ArithmeticException& e)
    {
        Exception::operator = (e);
        return *this;
    }
};

/**
  空指針異常
*/
class NullPointerException : public Exception
{
public:
    NullPointerException() : Exception(0) {}
    NullPointerException(const char* message) : Exception(message) {}
    NullPointerException(const char* file, int line) : Exception(file, line) {}
    NullPointerException(const char* message, const char* file, int line) : Exception(message, file, line) {}

    NullPointerException(const NullPointerException& e) : Exception(e) {}

    NullPointerException& operator = (const NullPointerException& e)
    {
        Exception::operator = (e);
        return *this;
    }
};

/**
  索引越界異常
*/
class IndexOutOfBoundsException : public Exception
{
public:
    IndexOutOfBoundsException() : Exception(0) {}
    IndexOutOfBoundsException(const char* message) : Exception(message) {}
    IndexOutOfBoundsException(const char* file, int line) : Exception(file, line) {}
    IndexOutOfBoundsException(const char* message, const char* file, int line) : Exception(message, file, line) {}

    IndexOutOfBoundsException(const IndexOutOfBoundsException& e) : Exception(e) {}

    IndexOutOfBoundsException& operator = (const IndexOutOfBoundsException& e)
    {
        Exception::operator = (e);
        return *this;
    }
};

/**
  內存不足異常
*/
class NoEnoughMemoryException : public Exception
{
public:
    NoEnoughMemoryException() : Exception(0) {}
    NoEnoughMemoryException(const char* message) : Exception(message) {}
    NoEnoughMemoryException(const char* file, int line) : Exception(file, line) {}
    NoEnoughMemoryException(const char* message, const char* file, int line) : Exception(message, file, line) {}

    NoEnoughMemoryException(const NoEnoughMemoryException& e) : Exception(e) {}

    NoEnoughMemoryException& operator = (const NoEnoughMemoryException& e)
    {
        Exception::operator = (e);
        return *this;
    }
};

/**
  非法參數異常
*/
class InvalidParameterException : public Exception
{
public:
    InvalidParameterException() : Exception(0) {}
    InvalidParameterException(const char* message) : Exception(message) {}
    InvalidParameterException(const char* file, int line) : Exception(file, line) {}
    InvalidParameterException(const char* message, const char* file, int line) : Exception(message, file, line) {}

    InvalidParameterException(const InvalidParameterException& e) : Exception(e) {}

    InvalidParameterException& operator = (const InvalidParameterException& e)
    {
        Exception::operator = (e);
        return *this;
    }
};

/**
  非法操作異常
*/
class InvalidOpeartionException : public Exception
{
public:
    InvalidOpeartionException() : Exception(0) {}
    InvalidOpeartionException(const char* message) : Exception(message) {}
    InvalidOpeartionException(const char* file, int line) : Exception(file, line) {}
    InvalidOpeartionException(const char* message, const char* file, int line) : Exception(message, file, line) {}

    InvalidOpeartionException(const InvalidOpeartionException& e) : Exception(e) {}

    InvalidOpeartionException& operator = (const InvalidOpeartionException& e)
    {
        Exception::operator = (e);
        return *this;
    }
};

}

#endif // EXCEPTION_H

源文件 Exception.cpp

#include "Exception.h"
#include <cstring>
#include <cstdlib>

using namespace std;

namespace MxLib
{

void Exception::init(const char* message, const char* file, int line)
{
    //無法確定 message 字符串的所處的內存空間,需要在堆空間中拷貝 message 字符串以保證
    this->message = strdup(message);

    if(NULL != file)
    {
        char sl[16] = {0};

        // 把行號轉為字符存放在sl數組裏
        itoa(line, sl, 10);

        this->location = static_cast<char*>(malloc(strlen(file) + strlen(sl) + 2));

        // 動態內存申請失敗不采取行動
        if (NULL != this->location)
        {
            this->message =strcpy(this->message, file);
            this->message=strcat(this->message, ":");
            this->message=strcat(this->message, sl);
        }
    }
    else
    {
        this->location = NULL;
    }
}

Exception::Exception(const char* message)
{
    init(message, NULL, 0);
}

Exception::Exception(const char* file, int line)
{
    init(NULL, file, 0);
}

Exception::Exception(const char* message, const char* file, int line)
{
    init(message, file, line);
}

/**
 * 拷貝構造函數和賦值重載符使用深拷貝
 */
Exception::Exception(const Exception& e)
{
    this->message = strdup(e.message);
    this->location = strdup(e.location);
}

Exception& Exception::operator= (const Exception& e)
{
    if (this != &e)
    {
        free(this->message);
        free(this->location);

        this->message = strdup(e.message);
        this->location = strdup(e.location);
    }
    return *this;
}

const char* Exception::getMessage() const
{
    return this->message;
}

const char* Exception::getLocation() const
{
    return this->location;
}

Exception::~Exception()
{
    free(this->message);
    free(this->location);
}
}

Cpp數據結構實戰開發2-基本類的構建