1. 程式人生 > >初始化的數值(int、double等)(一)

初始化的數值(int、double等)(一)

ng- private pub num 構造 ext signed 代碼 模板

首先考慮一個具有幾個構造函數的MyClass類。如果我們決定在這個類的私有部分加入一個新的數據成員,稱為int_data_:

class MyClass
{
public:
	MyClass()
		: int_data_(0)
	{}

	explicit MyClass(const Apple& apple)
		: int_data_(0)
	{}

	MyClass(const string& some_text,double weight)
		:int_data_(0),some_text_(some_text)
	{}

private:
	int int_data_;
	std::string some_text_;
};

加入這個新的數據成員時。須要做大量的工作。

每次加入一個內置類型的數據成員時。不要忘記在每一個構造函數中對它進行初始化(採用int_data_(0)這種形式)。其實,這是一種easy出錯的方法。假設忘了對這個數據成員進行初始化,它非常可能填充了垃圾信息,詳細取決於計算機和應用程序曾經的歷史。可能導致奇怪且非常難復制的行為。因此,為了防止這種錯誤。我們應該怎麽做?

首先我們討論下這個問題是與內置類型有關的。觀察std::string類型的數據成員some_text_。

當我們向MyClass類加入數據成員some_text_時。並不須要在MyClass類的每一個構造函數中對它進行初始化,由於std::string的默認構造函數將會被編譯器自己主動調用,把some_text_初始化為一個可反復的狀態(此例中為空字符串)。

可是內置類型並沒有構造函數,我們應該怎麽辦呢?事實上非常easy,對於類的數據成員。不要使用內置類型,而是使用類。例如以下:

  • 不要使用int,改用Int
  • 不要使用unsigned,改用Unsigned
  • 不要使用double。改用Double
以此類推。我們能夠看例如以下代碼,即模板類TNumber:

template <typename T>
class TNumber
{
public:
	TNumber(const T& x=0)
		: data_(x)
	{}

	operator T () const 
	{
		return data_;
	}

	TNumber& operator = (const T& x)
	{
		data_ = x;
		return *this;
	}

	//後綴操作符x++
	TNumber operator ++ (int)
	{
		TNumber<T> copy(*this);
		++data_;
		return copy;
	}

	//前綴操作符++x
	TNumber& operator ++ () 
	{
		++data_;
		return *this;
	}

	TNumber& operator += (T x)
	{
		data_ += x;
		return *this;
	}

	TNumber& operator 0= (T x)
	{
		data_ 0= x;
		return *this;
	}

	TNumber& operator *= (T x)
	{
		data_ *= x;
		return *this;
	}

	TNumber& operator /= (T x)
	{
		SCPP_TEST_ASSERT(x!=0,"Attept to divide by 0");
		data_ /= x;
		return *this;
	}

	T operator / (T x)
	{
		SCPP_TEST_ASSERT(x!=0,"Attept to divide by 0");		
		return data_ / x;
	}

private:
	T data_;
};

首先。接受T類型(T是不論什麽內置類型,比如int、double、float等)的構造函數。並沒有聲明explicit。

這是有意而為之的。這個類所聲明的下一個函數是operator T(),它同意把這個類的實例隱式轉換回相應的內置類型。這個類有意設計為非常easy在它與內置類型之間方便地來回轉換。它還定義了幾個常見的操作符。它們也是使用內置的數值類型時所期望使用的。

下面是我們能夠使用的實際類型的定義:

<span style="font-size:18px;">typedef TNumber<int> Int;
typedef TNumber<unsigned> Unsigned;
typedef TNumber<int64> Int64;
typedef TNumber<unsigned64> Unsigned64;
typedef TNumber<float> Float;
typedef TNumber<double> Double;
typedef TNumber<char> Char;</span>


我們應該如何使用像Int和Double這種新類型呢?它們看上去與內置類型相似,僅僅是以大寫字母開頭。這些類型的使用方法與相應的內置類型全然同樣。唯一的差別是它們都有一個默認構造函數把它們初始化為零。

這樣,以MyClass類為例,我們能夠採用下面的寫法:

class MyClass
{
public:
	MyClass()
	{}

	explicit MyClass(const Apple& apple)
	{}

	MyClass(const string& some_text,double weight)
		:some_text_(some_text)
	{}

private:
	Int int_data_;
	std::string some_text_;
};

在這裏。變量int_data_被聲明為以大寫字母開頭的Int類型,而不是int。這樣,我們就不須要在全部的構造函數中加入對它進行初始化的代碼。它將自己主動被初始化為零。

實際上另一個差別:當我們使用內置類型時,試圖將它除零可能導致不同的結果,詳細取決於編譯器和操作系統。為了保持一致。這個執行時錯誤將導致調用與處理其它錯誤同樣的錯誤處理函數,使我們能夠對錯誤進行調試。

健壯的代碼不應該在變量被初始化之前引用它們。可是,假設確實發生了這種情況。讓未初始化的變量具有一個像零這種安全值,顯然要比具有隨機的垃圾值好得多。

初始化的數值(int、double等)(一)