【问题标题】:overloading operator<< to change member variable重载运算符<<以更改成员变量
【发布时间】:2013-06-02 15:47:33
【问题描述】:

我有一个看起来像这样的类:

class A {
  public:
    A() {};
    A& operator<< (A& a, unsigned int i);

  private:
    vector<int> abc;
}

我想提供使用运算符向abc 添加对象的功能:

A a();
a << 3,4,5; // should do the same as several calls of abc.push_back(i)

我知道我必须重载&lt;&lt; 运算符,我是否也必须重载, 运算符?

实际的方法会是什么样子?

【问题讨论】:

  • 你就不能a &lt;&lt; 3 &lt;&lt; 4 &lt;&lt; 5吗?
  • 起初这也足够了。 , 运算符可能是一个很好的练习。我仍然对如何实际实现此方法有疑问。最后我尝试了一些错误,告诉我invalid number of operands
  • 那是因为您将operator &lt;&lt; 设为成员函数并使其接受 2 个参数。如果将其设为成员,只需指定一个参数 (int),第一个参数是隐式的。否则,将其声明为接受 2 个参数的 friend 函数
  • 是否有我们应该帮助您获胜的模糊 C++ 竞赛?
  • a &lt;&lt; 3,4,5; 的想法很难通过我的审查。即使只是

标签: c++ class operator-keyword


【解决方案1】:

永远不要在 C++ 中重载 , 运算符。语言允许这样做,但您不能这样做并保留操作员的预期行为。 (特别是,逗号运算符是 C++ 中的一个序列点:编译器保证左侧表达式将在右侧表达式之前计算。如果重载它,则不再保证将计算哪个表达式首先。)

您想使用流插入运算符的多次调用来插入多个对象。

(为了完整起见:您不应该重载的其他 C++ 运算符是 &amp;&amp;||。同样,不可能提供客户端代码所期望的行为(在这种情况下是短路)。

【讨论】:

  • 亚达亚达。 Boost做到了,我们也可以:)
  • 另外,不要重载一元&amp;
  • @jrok Boost 不是可以效仿的例子,至少对于很多组件来说不是。
  • @Potatoswatter 我倾向于同意,但我实际上发现了一个有意义的案例。智能指针,但指向 C 接口:指针的行为(有点)像 char*,所以它是 operator&amp; 返回 char**。 (虽然当时这似乎是个好主意,但我并不完全相信。)
  • @JamesKanze 原则上我同意 100%,但分配器和迭代器接口还不够成熟。当标准有足够的信心指定引用 std::vector&lt; bool &gt;::reference 会产生一个位指针时,那么对于普通用户来说这样做是安全的。
【解决方案2】:

如果您想保留a &lt;&lt; 1, 2, 3 的方面,您可以更改operator&lt;&lt; 的重载以接受intinitializer_list,而不是单个int

#include <initializer_list>

class A {
    public:
    A() {};
    A& operator<< (std::initializer_list<int> values);

    private:
    vector<int> abc;
}

然后像这样实现它:

A& A::operator<< (std::initializer_list<int> values)
{
    for(const auto& value : values)
        abc.push_back(value);
    return *this;
}

并简单地按如下方式使用它:

A a;
a << {1, 2, 3, 4};

您唯一需要确保的是您拥有提供这些功能的符合 C++11 的编译器。

【讨论】:

  • 非常好。使用初始化列表可以更好地解决这个问题(假设你有 C++11)。
  • 看起来是一个非常好的方法!根据@AndyProwls 对我的原始帖子的评论,有一个问题,operator&lt;&lt; 函数只需要一个参数?
  • 实际上我更改了方法的签名,因为它是一个成员,并且我添加了 return 语句。我希望它现在是正确的,但请告诉我是否需要更正。
【解决方案3】:

Eigen 库实现了这种语法。不确定您是否来自那里。

Eigen 是一个表达式模板库。它定义了看似做事的运算符和函数,但它们只是代理对象的工厂。代理构成编译时,有时是运行时数据结构,它们决定何时以及如何进行计算。

要实现这种语法,您需要代理对象。类似于std::ostreama &lt;&lt; 3 返回一个代理“流”对象,然后重载operator , 以启用, 4, 5 部分。代理也可以重载operator&lt;&lt;,在这种情况下,语法为a &lt;&lt; 3 &lt;&lt; 4 &lt;&lt; 5。这可以说是更干净,但 Eigen 是一个数学和运算符重载密集型库,, 具有作为最低优先级运算符的特殊位置,这减少了在 a &lt;&lt; 3, true? 4 : 42, 5 这样的初始化中出现优先级错误的可能性。

长话短说,即使您这样做,您也应该只使用operator&lt;&lt;

class A {
  public:
    A() {};

    inserter operator << (A& a, unsigned int i) {
      inserter ret( * this );
      ret , i;
      return ret;
    }

  private:
    vector<int> abc;

    struct inserter {
      A &client;

      inserter( A &in_client ) : client( in_client ) {}

      inserter &operator , ( int x ) {
        client.abc.push_back( x );
        return this;
      }
    };
    friend struct inserter;
};

【讨论】:

  • 这种方式是我想到但无法放入代码的一般方法。 :) 谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-05
  • 1970-01-01
相关资源
最近更新 更多