假设我有一个类,它包含了一些数学运算。让我们使用一个玩具示例
class Test
{
public:
Test( float f ) : mFloat( f ), mIsInt( false ) {}
float mFloat;
int mInt;
bool mIsFloat;
};
我想用以下原型创建一个运算符重载:
float operator=( const Test& test )
{
if ( !test.mIsFloat ) return *this; // in this case don't actually do the assignment
return test.mFloat; // in this case do it.
}
所以我的问题是:我可以使用内置返回类型重载operator =吗? 如果是这样,有没有办法引用内置类型?
我知道如果我用一个类包装内置函数,我可以这样做。但在这种情况下,我想让赋值运算符在LHS上使用内置类型
使用示例:
Test t( 0.5f );
float f = t; // f == 0.5
int i = 0;
i = t; // i stays 0.
更新:非常感谢您的帮助。从玩具示例中略微扩展,以便人们了解我真正想要做的事情。
我有一个配置系统,允许我从不同类型的参数树中获取配置参数(它们可以是整数,浮点数,字符串,数组等)。
我可以通过以下操作从树中获取项目:
float updateTime = config["system.updateTime"];
但是“system.updateTime”可能不存在。或者是错误的类型。通常,对于配置,我有一个默认值块,然后代码来覆盖配置中的默认值:
float updateTime = 10;
const char* logFile = "tmp.log";
... etc etc...
我想做类似的事情:
updateTime = config["system.updateTime"];
如果存在覆盖,则操作成功。因此,如果来自operator []的返回是树中的“无效”节点,则通常不会发生分配。
现在我用以下函数解决它:
getConfig( config, "system.updateTime", updateTime );
但我更喜欢使用赋值运算符。
如果我愿意创建包装内置函数的类,我可以这样做。
class MyFloat
{
operator=( const Test& test ) { if (test.isValidNode() ) f = test.float(); return *this; }
float f;
}
但显然,最好不要将带有普通类的内置函数用于重载赋值。问题是 - 这可能在c ++中吗?
答案 0 :(得分:3)
根据您的示例,您真正想要的是隐式转换运算符:
class Test
{
// ...
public:
operator float() const;
};
inline Test::operator float() const
{
return mIsFloat ? mFloat : mInt;
}
如果您想有条件地完成作业,那么您需要采取另一种方法。命名方法可能是最好的选择,所有事情都考虑在内......就像这样:
class Test
{
public:
bool try_assign(float & f) const;
};
inline bool Test::try_assign(float & f) const
{
if (mIsFloat) {
f = mFloat;
}
return mIsFloat;
}
无论你做什么,要小心你引入的语法糖不会导致代码不可读。
答案 1 :(得分:1)
您已经有一个从float
到Test
的隐式转换,转换构造函数的形式
class Test
{
public:
/* ... */
Test( float f ) : mFloat( f ) /*...*/ {}
};
支持转换,例如:
Test t(0.5f);
您可能还需要一个copy-assignement运算符,以便进一步从float
到Test
进行隐式转换:
class Test
{
public:
Test& operator=(float f) { mFloat = f; return *this; }
};
t = 0.75; // This is possible now
为了支持从Test
到float
的隐式转换,您不使用operator=
,而是使用自定义强制转换运算符,声明&如此实施:
class Test
{
public:
/* ... */
operator float () const { return mFloat; }
};
这使隐式转换成为可能,例如:
float f = t;
顺便说一下,你在这里发生了另一个隐含的转换,你甚至可能都没有意识到。在这段代码中:
Test t( 0.5 );
字面值0.5
不是float
,而是double
。为了调用转换构造函数,必须将此值转换为float
,这可能会导致精度损失。要指定float
文字,请使用f
后缀:
Test t( 0.5f );
答案 2 :(得分:1)
使用模板专精化:
class Config {
template<typename T>
void setValue(const std::string& index, T& value); //sets the value if available
};
template<float>
void Config::setValue(const std::string& index, float& value){...} //only sets float values
template<int>
void Config::setValue(const std::string& index, int& value){...} //only sets int values;
答案 3 :(得分:0)
您不能为基本类型“重载/添加”运算符,但您可以为类型Type
添加。但这不应该是operator =
而是operator >>
- 就像在istream
中一样。
class Test
{
public:
float mFloat;
int mInt;
bool mIsFloat;
Test& operator >> (float& v) { if (mIsFloat) v = mFloat; return *this; }
Test& operator >> (int& v) { if (!mIsFloat) v = mInt; return *this; }
};
然后你可以:
int main() {
float v = 2;
Test t = { 1.0, 2, false };
t >> v; // no effect
t.mIsFloat = true;
t >> v; // now v is changed
}
<强>更新强>
我想做类似的事情:
updateTime = config["system.updateTime"];
然后根据我的提议,你可以:
config["system.updateTime"] >> updateTime;