本文是根据 Safe C++, How to avoid common mistakes 中的例子总结而来。
熟悉C++的同学对构造函数初始化列表一定不会陌生,采用这种方法对类进行初始化不仅安全而且更有效率。不管数据成员是内置数据类型还是自定义的类型,我们也都非常习惯这种初始化的用法。
比如我们下面的类NormalClass有一个int型数据成员_data,而我们希望将其默认值填成0。需要在默认构造函数中初始化列表中赋初值0。例如如下代码:
比如我们下面的类NormalClass有一个int型数据成员_data,而我们希望将其默认值填成0。需要在默认构造函数中初始化列表中赋初值0。例如如下代码:
/*NormalClass.h*/
#ifndef _NORMAL_CLASS_
#define _NORMAL_CLASS_
class NormalClass
{
public:
NormalClass():_data(0)
{}
NormalClass(int value):_data(value)
{}
int GetData()
{
return _data;
}
private:
int _data;
};
#endif
但是如果你打算编写更安全的代码,Safe C++书中给出的建议是对基本数据类型进行安全的封装,根据C++ RAII的特性使得初始化的过程既是赋默认值的过程。
/*SafeTypeClass.h*/
#ifndef _SAFE_TYPE_CLASS_
#define _SAFE_TYPE_CLASS_
#include <iostream>
#include "Safe_Types.h"
using namespace std;
class SafeTypeClass
{
public:
SafeTypeClass()
{}
SafeTypeClass(const Int& value):_int_data(value)
{}
Int GetData()
{
return _int_data;
}
private:
Int _int_data;
};
#endif
以下是根据Safe C++书中的给出的封装代码改造和简化而来:
/*Safe_Types.h*/
#ifndef _SAFE_TYPE_H_
#define _SAFE_TYPE_H_
#include <iostream>
using namespace std;
template <typename T>
class SafeTypeNumber
{
public:
SafeTypeNumber(const T& x =0)
:_data(x){}
operator T ()const
{
return _data;
}
SafeTypeNumber& operator =(const T& num)
{
_data = num;
return *this;
}
SafeTypeNumber operator++(int)
{
SafeTypeNumber<T> ret(*this);
_data++;
return ret;
}
SafeTypeNumber& operator++()
{
_data++;
return *this;
}
SafeTypeNumber& operator+=(T value)
{
_data += value;
return *this;
}
SafeTypeNumber& operator-=(T value)
{
_data -= value;
return *this;
}
SafeTypeNumber& operator*=(T value)
{
_data *= value;
return *this;
}
SafeTypeNumber& operator/=(T value)
{
if(!value)
{
cout<<"ERROR:Attempt to divide by 0"<<endl;
//TODO: Throw exception
system("PAUSE");
exit(1);
}
_data /= value;
return *this;
}
T operator/(T value)
{
if(!value)
{
cout<<"ERROR:Attempt to divide by 0"<<endl;
//TODO: Throw exception
system("PAUSE");
exit(1);
}
return _data/value;
}
private:
T _data;
};
typedef long long int64;
typedef unsigned long long unsigned64;
typedef SafeTypeNumber<int> Int;
typedef SafeTypeNumber<unsigned> Unsigned;
typedef SafeTypeNumber<int64> Int64;
typedef SafeTypeNumber<unsigned64> Unsigned64;
typedef SafeTypeNumber<float> Float;
typedef SafeTypeNumber<double> Double;
typedef SafeTypeNumber<char> Char;
#endif
最后,我们编写一个主函数验证一下我们的代码是不是可以满足我们的期望:
#include <iostream>
#include "SafeTypeClass.h"
#include "NormalClass.h"
using namespace std;
int main()
{
SafeTypeClass cls_one;
cout<<"cls_one‘s data: "<<cls_one.GetData()<<endl;
SafeTypeClass cls_two(10);
cout<<"cls_one‘s data: "<<cls_two.GetData()<<endl;
Int temp_a = cls_two.GetData();
Int temp_b = temp_a/0;
NormalClass normal_a;
cout<<"normal_a‘s data: "<<normal_a.GetData()<<endl;
NormalClass normal_b(20);
cout<<"normal_b‘s data: "<<normal_b.GetData()<<endl;
system("PAUSE");
return 0;
}