关于单一参数构造函数的问题,主要是因为单一参数被编译器用作隐式类型转换,从而导致一些不可预期的事件的发生,请参见代码详细注释:
/*
* 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关键字。