如何使用内置返回类型重载运算符?

时间:2012-10-30 17:36:39

标签: c++

假设我有一个类,它包含了一些数学运算。让我们使用一个玩具示例

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 ++中吗?

4 个答案:

答案 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)

您已经有一个从floatTest的隐式转换,转换构造函数的形式

class Test
{
public:
 /* ... */
Test( float f ) : mFloat( f ) /*...*/ {}       

};

支持转换,例如:

Test t(0.5f);

您可能还需要一个copy-assignement运算符,以便进一步从floatTest进行隐式转换:

class Test
{
public:

    Test& operator=(float f) { mFloat = f; return *this; }  
};

t = 0.75; // This is possible now

为了支持从Testfloat的隐式转换,您不使用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;