通过级联调用来增加值

时间:2017-12-16 22:30:39

标签: c++ increment

有人可以解释这段代码吗?我不明白c2的值是如何只有1。

    class Test
{
private:
    static int c1;
    int c2 = 0;
public:
    Test fun();
    int getC1() { return c1; }
    int getC2() { return c2; }
};
int Test::c1 = 0;
Test Test::fun()
{
    c2 += ++Test::c1;
    return *this;
}
int main()
{
    Test t;
    Test t2 = t.fun().fun().fun().fun();
    cout << t.getC1() << " " << t.getC2();
    return 0;
}

感谢。

2 个答案:

答案 0 :(得分:1)

fun()会返回调用它的对象的副本。下一个调用是返回值。

即,这段代码:

Test t2 = t.fun().fun().fun().fun();

等同于此代码:

Test temp1 = t.fun();
Test temp2 = temp1.fun();
Test temp3 = temp2.fun();
Test t2 = temp3.fun();

fun()递增调用它的实例的c2变量,然后返回一个副本。这意味着第一次调用会增加t的值,temp1的第二个值,temp2的第三个等等。创建的副本具有相同的c2价值作为来源。

正如您所看到的,t.c2仅增加一次。

答案 1 :(得分:0)

  

有人可以解释这段代码吗?我不明白怎么做   c2的值只有1。

我更喜欢gdb,但我会抵制与(编译器提供的)默认ctor,dtor等相结合的匿名实例。似乎没有地方可以设置一个断点或cout或者进入...在assy级别上工作太多。

您可以考虑的替代方案是添加一些诊断cout ...以及复制和移动ctors和dtor与诊断couts。

也许:

#include <iostream>

class Test
{
private:
   int        m_seq;
   int        c2;
   static int c1;

public:
   Test()                    // default ctor
      : m_seq(++M_seq)
      , c2 (0)
      {
         std::cout << "\n  ctor  " << show() << std::flush;
      }

   Test(const Test& rhs)     // copy ctor
      : m_seq(++M_seq)       // unique seq id
      , c2 (rhs.c2)
      {
         std::cout << "\n  cctor " << show() << std::flush;
      }

   Test(const Test&& rhs)    // move ctor       (4)
      : m_seq(++M_seq)       // unique seq id
      , c2 (rhs.c2)
      {
         std::cout << "\n  mctor " << show() << std::flush;
      }  // tbd - new to me, should this be something with std::move() ?

   ~Test()                   // default dtor
      {
         std::cout << "\n  dtor  " << show() << std::flush;
      }

   Test fun();

   int getC1() { return c1; }
   int getC2() { return c2; }

   std::string show()
      {
         std::string s;
         s = " show()  seq: " + std::to_string(m_seq)
            + "    c1: " + std::to_string(c1)
            + "    c2: " + std::to_string(c2);
         return (s);
      }

public:
   static int M_seq; // diagnostic only

private:
   // coding standard - disallow when not used
   Test& operator= (const Test&)  = delete; // copy assignment (5)
   Test& operator= (const Test&&) = delete; // move assignment (6)

};

int Test::c1    = 0;
int Test::M_seq = 0;

Test Test::fun()
{
   c2 += ++Test::c1;

   // diagnostic only
   std::cout << "\n  fun() " << show() << std::flush;

   return *this;
}

int main(int, char**)
{
   // confirm initial seq state
   std::cout << "\n  -- init M_seq " << Test::M_seq << std::endl;

   Test t;

   Test t2 = t.fun().fun().fun().fun();

   std::cout << "\n\n   t final " << t.show() << std::endl; 
   std::cout <<  "\n  t2 final " << t2.show() << std::endl;
   // note how easy to ignore getters - 
   // see http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html

   // final seq state
   std::cout << "\n\n  - final M_seq " << Test::M_seq << std::endl;
}

带输出:

  -- init M_seq 0

  ctor   show()  seq: 1    c1: 0    c2: 0
  fun()  show()  seq: 1    c1: 1    c2: 1
  cctor  show()  seq: 2    c1: 1    c2: 1
  fun()  show()  seq: 2    c1: 2    c2: 3
  cctor  show()  seq: 3    c1: 2    c2: 3
  fun()  show()  seq: 3    c1: 3    c2: 6
  cctor  show()  seq: 4    c1: 3    c2: 6
  fun()  show()  seq: 4    c1: 4    c2: 10
  cctor  show()  seq: 5    c1: 4    c2: 10
  dtor   show()  seq: 4    c1: 4    c2: 10
  dtor   show()  seq: 3    c1: 4    c2: 6
  dtor   show()  seq: 2    c1: 4    c2: 3

   t final  show()  seq: 1    c1: 4    c2: 1

  t2 final  show()  seq: 5    c1: 4    c2: 10


  - final M_seq 5

  dtor   show()  seq: 5    c1: 4    c2: 10
  dtor   show()  seq: 1    c1: 4    c2: 1
  

c2的值仅为1

此输出列出了ctor,fun()和cctor调用。

现在每个匿名对象都会打印出唯一的m_seq,因此seq id应该有助于查看&#39; action&#39;发生。

第一个ctor获得1的seq ...第一个fun()也是seq 1 - 有意义。

fun()的后续调用是在不同的实例中,最后3个是匿名的,这使调试变得混乱。

你是对的 - 第一个实例(用seq 1)以c2值1结束。不用以后fun()改变它。

你也是对的,最后一个实例(用seq 5)以c2值10结束。

按顺序连接4个fun(),最后3个创建&#39;临时&#39;测试的匿名实例,以及他们在同一行上的2,3和4 dtor。

这种技术(用诊断couts检测代码)很常见。在任何带有bool的诊断cout之前启用/禁用更正式的测试...在bool标识符之前添加,以便在您不希望发送噪声时轻松查找/删除。 (在生产代码中,我使用了基于ram的循环日志。要发送,此日志在系统启动时被禁止,并且缺少日志会取消额外的cout活动。)

你可以通过让Test :: fun()返回指向实例的指针来改变这段代码的行为:Test *。该函数当前返回一个Test实例(即* this),因此编译器生成一个cctor来构造该新的匿名实例。返回this指针会将fun()链更改为fun() - &gt; fun() - &gt; fun() - &gt; fun()。

希望这会有所帮助。