cast operator() - 强制转换为引用并转换为值

时间:2015-11-20 15:53:32

标签: c++ casting reference copy

我的关注点正在触及标题中的主题。

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

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

现在我们可以使用这个代表int的类,当然在使用这个类时没有更大的意义,但它只是一个例子。如果希望这个类的行为更像真实整数,那么我们应该提供强制转换运算符(不提运算符==,>,<等等),这是我的关注,因为我可以定义两个运算符:

operator T() {return m_value;}
operator T&() {return 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;
};

但它可以是:

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;
};

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

当然,引用转换似乎更有效,但我不确定它是否总是以它应该工作的方式工作。请以某种方式告诉我并说,为什么一个运营商比另一个运营商好?

3 个答案:

答案 0 :(得分:3)

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

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

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类在以下情况下使用:

#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;
}

编译&amp;运行: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

答案 1 :(得分:3)

我同意上述两个答案。人们应该总是喜欢最小化直接操纵一个表示的函数的数量 对象并通过引用公开它(为什么在上面的两个答案和注释中也有解释)。当真正需要访问表示时,例如operator + =,那么可以通过固有地修改值来实现他们在班级中的第一个论点。

基于其参数值(例如+)生成新值的运算符可以在类外部定义,并在其实现中使用基本运算符。

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 +=
}

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

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); }
    };

据我所知,这里我们不需要访问代表,也不需要通过引用返回。

上面的所有例子都涉及一个非常小的对象。但是当处理繁重的对象时,复制操作确实非常昂贵,需要程序员来决定。如果我们想避免复制成本,我们可以传递参考和返回参考,但......

  1. 对结果的引用将作为a传递出函数 引用返回值,返回值不能是 自动变量。

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

  3. 所以,结果通常会在免费商店分配。复制 返回值通常比分配和(最终)释放免费商店上的对象更便宜(在执行时间,代码空间和数据空间中)。(#11.6 over.large #C++ Programming Language)

    这些主题总是值得商榷,但我们需要确保的是安全性和无泄漏,这将导致更多控制,减少未来的痛苦。

答案 2 :(得分:1)

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

如果你返回const引用,这不会是问题。关于intconst int&之间的选择,它实际上并不重要 - 它们在所有情况下的行为都完全一样。

如果您定义到某个重类的转换,这将更有趣。这样做时,您将看到两个选项 - 通过const引用返回 - 但这意味着,它不可能在返回值上调用非const限定方法。如果按值返回,则会产生复制构造函数的成本。选择取决于课堂设计。

还有一个返回引用的生命周期问题 - 但这通常不是问题,除非代码变得非常棘手(您需要将返回的引用存储为类的成员以解决此问题)。