casting operator() - 转换为引用并转换为值

casting operator() - cast to reference and cast to value

我的问题涉及标题中给出的主题。

假设我们有一些非常简单的class

class Integer{
public:
    Integer(int number) : m_value(number) {}
    int value(){return m_value;}
private:
    int m_value;
};

现在我们可以用这个class,它代表int,当然用这个class也没什么意义,只是举个例子。如果想让这个 class 表现得更像一个真正的整数,那么我们应该提供转换运算符(不提及运算符 ==、>、< 等),这是我关心的,因为我可以定义两个运算符:

operator T() {return m_value;}
operator T&() {return m_value;}

一些最简单的示例可以编译并与它们(第一个或第二个)一起工作,因此我们的 class 可以如下所示:

class Integer{
public:
    Integer(int number) : m_value(number) {}
    int value(){return m_value;}
    operator T(){return m_value;} // casting operator
private:
    int m_value;
};

但可以是:

class Integer{
public:
    Integer(int number) : m_value(number) {}
    int value(){return m_value;}
    operator T&(){return m_value;} // casting operator
private:
    int m_value;
};

同样,所以我的问题是这两个哪个合适?当然我不能同时拥有它们,因为编译器无法识别使用哪一个。

自然引用转换似乎更有效,但我不确定它是否始终按应有的方式工作。请以某种方式告诉我,为什么一个操作员比另一个更好?

您的示例中定义的引用转换相当无用 - 您 return 对内部成员的可修改引用,因此违反了封装原则。

如果您 return const 引用代替,这将不是问题。至于 intconst int& 之间的选择,这真的不重要——它们在所有情况下的行为都完全相同。

如果您将转换定义为一些重 class,这将更有趣。这样做时,您将看到两个选项 - return by const reference - 但这意味着,不可能在 returned 值上调用非 const 限定方法。如果按值 return,您将承担复制构造函数的费用。选择将由 class 设计决定。

还有一个 returned 引用的生命周期问题 - 但这通常不是问题,除非代码变得非常棘手(您需要将 returned 引用存储为class 的成员遇到了这个问题。

事实上,您两者都需要,稍作调整,编译器就会知道选择哪个。所有的魔力都在于您可以(并且应该在有意义的时候)将成员函数定义为 constid est 可从常量对象调用。

因此,您的 Integer class 应该看起来像

class Integer
{
public:
    Integer() : Integer(0) {}
    Integer(int number) : m_value(number) {}
    Integer(const Integer& other) : m_value(other.value()) {}
    int value() const { return m_value; }

    operator int() const { return m_value; }
    operator int&() { return m_value; }
    const Integer& operator=(const Integer& other) { m_value = other; return *this; }
private:
    int m_value;
};

此定义将允许 Integer class 在以下情况下可用:

#include <iostream>
int main()
{
    const Integer zero;
    const Integer one(1);
    Integer counter;

    counter = zero + one;
    std::cout << "counter: " << counter << std::endl;

    counter++;
    std::cout << "counter: " << counter << std::endl;

    for (Integer i=0 ; i < counter ; ++i)
    {
        std::cout << "i: " << i << std::endl;
    }

    return zero;
}

编译 & 运行: g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out

输出:

counter: 1
counter: 2
i: 0
i: 1

实例:http://coliru.stacked-crooked.com/a/641fe02e70c02920

我同意以上两个答案。人们应该总是倾向于尽量减少直接操纵一个表示的函数的数量。 对象并通过引用公开相同的对象(为什么在上面的两个答案和评论中也有解释)。当确实需要访问表示时,例如运算符+ =,则可以通过固有地修改值来实现他们在 class 本身的第一个参数。

可以在 class 之外定义仅根据其参数值生成新值的运算符,例如 +,并在其实现中使用基本运算符。

class complex{
     double re,im;
     public:
     complex& operator+=(complex a);//needs access to representation.

};
complex operator+(complex a,complex b)
{
  complex r=a;
  return r+=b; //access representation through +=
}

现在来到你的运营商,类型转换,你真的需要访问表示吗?首先,我们什么时候需要实现类型转换?举个简单的例子:

class Cents
{
private:
    int m_nCents;
public:
    Cents(int nCents=0)
    {
        m_nCents = nCents;
    }
};


class Dollars
    {
    private:
        int m_nDollars;
    public:
        Dollars(int nDollars=0)
        {
            m_nDollars = nDollars;
        }

         // Allow us to convert Dollars into Cents
         operator Cents() { return Cents(m_nDollars * 100); }
    };

根据我的说法,这里我们不需要访问表示,也不需要通过引用 return。

上面的所有例子都处理了一个在 size.But 中非常小的对象,当处理重对象时,复制操作确实可能非常昂贵,这取决于程序员 decide.If 我们想要为了避免复制成本,我们可以传递参考和 return 参考但是...

  1. 对结果的引用将作为 引用 return 值,return 值不能是 自动变量.

  2. 由于一个运算符经常在一个表达式中使用多次,因此 结果不能作为静态局部变量。

所以,结果通常会分配在空闲 store.Copying return 值(在执行时间、代码 space 和数据 space 方面)通常比在自由存储上分配和(最终)释放对象更便宜。(#11.6 over.large #C++ Programming Language).

这些话题总是有争议的,但我们需要确保的是安全性和无泄漏,这会导致未来更多的控制和更少的痛苦。