我想了解以下代码:
blueberry bitCopy(blueberry a) {
cout << "bitCopy " << blueberry::blQuantity << endl;
return a;
}
void howMany() {
cout << blueberry::blQuantity << endl;
}
int main() {
blueberry firstBl;
howMany();
bitCopy(firstBl);
howMany();
}
班蓝莓:
#ifndef header_h
#define header_h
#pragma once
#include <string>
#include <iostream>
using namespace std;
class blueberry {
private:
static int blQuantity;
public:
blueberry();
~blueberry() {
blQuantity--;
}
friend blueberry bitCopy(blueberry a);
friend void howMany();
};
#endif
int blueberry::blQuantity = 0;
blueberry::blueberry() {
blQuantity++;
};
类蓝莓只是一个具有静态int值blQuantity的类,每次创建一个对象时它都会在构造函数中递增,并且每次对象超出作用域时都会在析构函数中递减。
该程序的读出是:
1
bitCopy 1
-1
我最后期待0而不是-1。有人可以解释一下吗?
请不要告诉我我需要复制构造函数。我不是要修复此代码,以便对象计数起作用。我试图理解它是如何工作的,以及为什么blQuantity不是我期望的价值。
答案 0 :(得分:2)
类蓝莓只是一个具有静态int值blQuantity的类,每次创建一个对象时它都会在构造函数中递增,并且每次对象超出作用域时都会在析构函数中递减。
您是否确定每次创建一个?我认为你有一些错过的东西。
blueberry bitCopy(blueberry a)
那是值得传递的;即,blueberry a
这里是提交给bitCopy()
的内容的副本。这会调用蓝莓的 copy constructor ,您尚未定义。因此,编译器为您创建一个简单的编译器,它复制原始对象中的任何成员值 - 但它不会增加任何内容。如果你想要,你必须定义:
blueberry::blueberry (const blueberry&) // copy constructor
blueberry& operator= (const blueberry&) // copy assignment operator
您可能还需要移动构造函数和移动赋值运算符 - 请参阅维基百科关于三(或五)&#34;规则的文章。 我在上一段中链接了。
最后blQuantity
为-1的原因是因为实际上有{em>两个副本用bitCopy()
制作,一个用于参数,一个用于返回值。如果您将其更改为:
blueberry bitCopy (blueberry &a)
即,使用pass-by-reference,只有一个副本,blQuantity
之后将为0。如果您再返回值void
,则不会制作副本,blQuantity
应为1。
这里展示了复制构造函数和operator=
(复制赋值运算符)的作用:
#include <iostream>
#include <string>
using namespace std;
class A {
public:
string x;
A (string s) : x(s) {
cout << "A con " << "(" << x << ")\n";
}
A (const A& other) : x(other.x) {
x.append("-copy");
cout << "A copy " << "(" << x << ")\n";
}
A& operator= (const A& other) {
x = other.x;
x.append("[=]");
cout << "A assign " << "(" << x << ")\n";
return *this;
}
~A () { cerr << x << " A bye!\n"; }
};
A test (A a) {
return a;
}
int main (void) {
A a("#1");
cout << "test()\n";
A b = test(a);
cout << "Copy assign:\n";
b = a;
cout << "Exiting...\n";
return 0;
}
我将逐步完成输出:
A con (#1)
test()
A copy (#1-copy)
A copy (#1-copy-copy)
#1-copy A bye!
第一行来自A a("#1")
。最后三行是A b = test(a)
的结果。第一个是复制参数A test (test a)
。第二个是创建返回值,它是参数的副本,因此对象上的标记现在是#1-copy-copy
。这会初始化b
中的main()
。当test()
退出时,参数对象将被销毁#1-copy A bye!
。
Copy assign:
A assign (#1[=])
这来自b = a
中的main()
。 请注意,之前版本的b
未被销毁。这是因为复制分配是指将一个对象转换为另一个对象的副本。两个对象都没有被销毁,但是目标对象的内容可能会改变,因此b
标签现在是#1[=]
。可以预见:
Exiting...
#1[=] A bye!
#1 A bye!
当程序结束时,a
和b
将被销毁。
如果您将test()
的签名更改为:
A& test (A &a)
您将获得此输出:
A con (#1)
test()
A copy (#1-copy)
Copy assign:
A assign (#1[=])
Exiting...
#1[=] A bye!
#1 A bye!
只创建了两个对象,a
通过构造函数创建,b
通过复制con;它们都不会在结束前被销毁。如果您不使用test()
的返回值,则只创建一个对象。