關于單一參數構造函數的問題,主要是因為單一參數被編譯器用作隱式類型轉換,從而導致一些不可預期的事件的發生,請參見代碼詳細注釋:
/*
* single_argument_ctor.cpp
*
* Created on: 2010-3-29
* Author: Volnet
* Compiler: GNU C++(version 3.4.5)
* MSVC CL(version 15.00.30729.01)
*/
#include <stdlib.h>
#include <iostream>
#include <sstream>
// single-argument class
class SingleArgumentClass {
private:
int _inner;
public:
SingleArgumentClass()
:_inner(-1)
{
}
SingleArgumentClass(int actual)
:_inner(actual)
{
}
bool operator==(const SingleArgumentClass& rhs);
std::string str(){
// we'd better to use boost::lexical_cast to cast.
// #region cast
std::stringstream strStream;
strStream << _inner;
std::string str;
strStream >> str;
// #endregion
return str;
}
};
bool
SingleArgumentClass::operator ==(const SingleArgumentClass& rhs){
if(_inner == rhs._inner)
return true;
return false;
}
// single-argument class fixed bug by explicit keyword.
class SingleArgumentClassFixedBugByExplicitKeyword {
private:
int _inner;
public:
SingleArgumentClassFixedBugByExplicitKeyword()
:_inner(-1)
{
}
explicit SingleArgumentClassFixedBugByExplicitKeyword(int actual)
:_inner(actual)
{
}
bool operator==(const SingleArgumentClassFixedBugByExplicitKeyword& rhs);
std::string str(){
// we'd better to use boost::lexical_cast to cast.
// #region cast
std::stringstream strStream;
strStream << _inner;
std::string str;
strStream >> str;
// #endregion
return str;
}
};
bool
SingleArgumentClassFixedBugByExplicitKeyword::operator ==(const SingleArgumentClassFixedBugByExplicitKeyword& rhs){
if(_inner == rhs._inner)
return true;
return false;
}
// single-argument class fixed bug by helper class.
class ActualType {
public:
ActualType(int value):_value(value){};
int get_value(){ return _value; }
private:
int _value;
};
class SingleArgumentClassFixedBugByHelperClass {
private:
int _inner;
public:
SingleArgumentClassFixedBugByHelperClass()
:_inner(-1)
{
}
SingleArgumentClassFixedBugByHelperClass(ActualType actual)
:_inner(actual.get_value())
{
}
bool operator==(const SingleArgumentClassFixedBugByHelperClass& rhs);
std::string str(){
// we'd better to use boost::lexical_cast to cast.
// #region cast
std::stringstream strStream;
strStream << _inner;
std::string str;
strStream >> str;
// #endregion
return str;
}
};
bool
SingleArgumentClassFixedBugByHelperClass::operator ==(const SingleArgumentClassFixedBugByHelperClass& rhs){
if(_inner == rhs._inner)
return true;
return false;
}
void Assert(bool status,
std::string strTrue = std::string("assert result is true;"),
std::string strFalse = std::string("assert result is false;"));
int main(void){
SingleArgumentClass obj(3);
std::cout << obj.str() << std::endl;
// our purpose.
SingleArgumentClass obj1(1);
SingleArgumentClass obj2(1);
Assert(obj1 == obj2, "obj1 == obj2", "obj1 != obj2");
int i = 3;
// warning!!!
// obj is a SingleArgumentClass object.
// i is a integer.
// operator== only define the equal between two SingleArgumentClass object.
// In fact:
// obj == i:
// 1.compiler found the operator== require two SingleArgumentClass object.
// 2.compiler try to find a cast method for casting int to SingleArgumentClass.
// 3.compiler found it can use the SingleArguementClass.Ctor(int)
// to create a new SingleArgumentClass.
// 4.compiler try to create a new SingleArgumentClass object from i.
// 5.so it without any warning and error, but it's logical not we need.
Assert(obj == i, "obj == i //right?", "obj != i");
// Assert(i == obj); // Compile ERROR: no match for 'operator==' in 'i == obj'
// it's may encounter a compile-time error.
// GNU G++: no match for 'operator==' in 'objFixed == i' single_argument_ctor.cpp single_argument_ctor/src 106 C/C++ Problem
// MSVC: 錯誤 1 error C2679: 二進制“==”: 沒有找到接受“int”類型的右操作數的運算符(或沒有可接受的轉換) {projectpath}\single_argument_ctor\src\single_argument_ctor.cpp 107 single_argument_ctor
SingleArgumentClassFixedBugByExplicitKeyword objFixed(3);
// Assert(objFixed == i, "objFixed == i", "objFixed != i");
SingleArgumentClassFixedBugByHelperClass objFixedByHelper1(3);
SingleArgumentClassFixedBugByHelperClass objFixedByHelper2(3);
// it's may encounter a compile-time error.
// GNU G++: no match for 'operator==' in 'objFixedAuto1 == i' single_argument_ctor.cpp single_argument_ctor/src 158 C/C++ Problem
// MSVC: 錯誤 1 error C2679: 二進制“==”: 沒有找到接受“int”類型的右操作數的運算符(或沒有可接受的轉換) {projectpath}\single_argument_ctor\src\single_argument_ctor.cpp 163 single_argument_ctor
// Assert(objFixedByHelper1 == i);
}
void Assert(bool status,
std::string strTrue, std::string strFalse)
{
std::cout << (status strTrue : strFalse) << std::endl;
}
解決方法:
1、explicit關鍵字,在單參數構造函數前使用explicit參數,可以避免單參數構造函數被用于隱式轉換。
2、利用中間類的方式,詳見代碼“SingleArgumentClassFixedBugByHelperClass相關部分”。如果編譯器不支持解決方法1,則建議使用此方法。上面代碼所提及的兩款主流編譯器均支持explicit關鍵字。