有人可以解释这段代码吗?我不明白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;
}
感谢。
答案 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()。
希望这会有所帮助。