- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
来自 Bjarne Stroustrup 的 C++ 编程语言第 4 版:
3.3.4。抑制操作
对层次结构中的类使用默认复制或移动通常是一场灾难:只给出一个指向基的指针,我们根本不知道派生的成员是什么类有(§3.2.2),所以我们不知道如何复制它们。所以,最好的办法通常做的是删除默认的复制和移动操作,即消除这两个操作的默认定义:
class Shape {
public:
Shape(const Shape&) =delete; // no copy operations
Shape& operator=(const Shape&) =delete;
Shape(Shape&&) =delete; // no move operations
Shape& operator=(Shape&&) =delete;
~Shape();
// ...
};
为了理解他的意思,我创建了以下示例:
#include <iostream>
using namespace std;
class Person {
private:
int age;
public:
Person(const int& Age) : age {Age} {};
Person(const Person& from) : age {from.Age()} { cout << "copy constructor" << endl; };
Person& operator=(const Person& from) { cout << "copy assignment" << endl; age = from.Age(); return *this; }
virtual void Print() { cout << age << endl; };
void Age(const int& Age) { age = Age; };
int Age() const { return age; };
};
class Woman : public Person {
private:
int hotness;
public:
Woman(const int& Age, const int& Hotness) : Person(Age), hotness {Hotness} {};
Woman(const Woman& from) : Person(from), hotness {from.Hotness()} { cout << "copy constructor of woman" << endl; };
Woman& operator=(const Woman& from) { Person::operator=(from); cout << "copy assignment of woman" << endl; hotness = from.Hotness(); return *this; };
void Print() override { cout << Age() << " and " << hotness << endl; };
int Hotness() const { return hotness; };
};
int main() {
Woman w(24, 10);
Person p = w;
p.Print();
return 0;
}
这个版本程序的输出是:
copy constructor
24
作为菜鸟,这对我来说有点意外,但后来我意识到,因为 p 不是指针,所以没有使用虚拟表,而且因为它是一个人,Person::Print() 被调用了.所以我知道 Person 的复制构造函数被调用了,但我不知道 Woman 的复制构造函数是否被调用了,但这并不重要,因为 p 是一个 Person,通过它我永远无法访问对女人::性感,即使我尝试了类型转换也不行。
所以我认为他可能只是在谈论指针,所以我尝试了这个:
int main() {
Woman w(24, 10);
Person* p = new Person(20);
p->Print();
p = &w;
p->Print();
return 0;
}
新的输出是:
20
24 and 10
现在 p 是一个指针,因为它是一个指针,所以不会进行复制或移动,只会更改引用。
然后我想我可以尝试取消引用 p 并将 w 分配给它:
int main() {
Woman w(24, 10);
Person* p = new Person(20);
p->Print();
*p = w;
p->Print();
return 0;
}
输出是这样的:
20
copy assignment
24
我认为对 p->Print() 的第二次调用会调用 Woman::Print(),因为 p 指向一个 Woman,但事实并非如此。知道为什么吗?来自 Person 的复制任务被调用了,我想是因为 p 是一个 Person*。
然后我试了一下:
int main() {
Woman w(24, 10);
Person* p = new Woman(20, 7);
p->Print();
*p = w;
p->Print();
return 0;
}
新的输出是这样的:
20 and 7
copy assignment
24 and 7
所以我猜因为 p 是 Person* Person 的复制分配被调用,而不是 Woman 的复制分配。奇怪的是,年龄更新了,但热度值保持不变,我不知道为什么。
再试一次:
int main() {
Woman w(24, 10);
Woman* p = new Woman(20, 7);
p->Print();
*p = w;
p->Print();
return 0;
}
输出:
20 and 7
copy assignment
copy assignment of woman
24 and 10
现在数字似乎是正确的。
我的下一步是删除对 Person 的复制赋值的实现,看看是否会调用默认值:
//Person& operator=(const Person& from) { cout << "copy assignment" << endl; age = from.Age(); return *this; }
输出:
20 and 7
copy assignment of woman
24 and 10
请注意,年龄被复制了,所以不用担心。
下一个明显的举措是删除 Woman 的复制分配的实现,看看会发生什么:
//Woman& operator=(const Woman& from) { Person::operator=(from); cout << "copy assignment of woman" << endl; hotness = from.Hotness(); return *this; };
输出:
20 and 7
24 and 10
一切似乎都很好。
所以此时我不太明白作者的意思,所以如果有人能帮助我,我将不胜感激。
谢谢。
密件抄送。
最佳答案
Woman w(24, 10);
Person p = w;
p.Print();
24
Which was a bit of a surprise for me, being a noob, but then a realized that since p is not a pointer, the virtual table is not used, and since it's a Person, Person::Print() got called.
正确
So I knew that the copy constructor for Person got called, but I couldn't know if the copy constructor for Woman got called,...
不,它没有。
...but that wouldn't really matter, since p is a Person, and through it I'd never have access to Woman::Hotness, not even if I tried a cast.
考虑 Person p =
行创建了一个新变量 p
,它具有足够的内存字节来存储 Person
的数据。如果您调用复制构造函数 Person::Person(const Person&);
代码只知道 Person 的数据成员 - 而不是任何派生类型的数据成员 - 所以“切片” Woman
对象复制构成 Person
的数据成员。没有地方放hotness
,也没有被复制。
Person* p = new Person(20);
p->Print();
*p = w;
p->Print();
20
copy assignment
24I thought the second call to p->Print() would call Woman::Print() since p was pointing to a Woman, but it didn't. Any idea why? The copy assignment from Person got called, I think because p is a Person*.
*p
指的是您刚刚分配的 Person
对象。 new
仅被告知有关 Person
- 它无法知道您可能想要/期望/希望有额外的空间来放置 Woman 的额外字段
稍后可以复制,因此它只是为 Person
分配了空间。当您编写 *p = w;
时,它仅复制属于 Person
的字段,使用 Person::operator=(const Person&)
功能。这不会设置指向虚拟调度表的指针来寻址Woman
的表...同样没有Woman
的知识...这就是为什么即使是 >像
函数以后不会被解析为 Print
这样的虚拟Woman::Print
。
Person* p = new Woman(20, 7);
p->Print();
*p = w;
p->Print();
20 and 7
copy assignment
24 and 7So I guess because
p
isPerson*
the copy assignment for Person got called, but not the one for Woman. Weirdly enough, the age got updated but the value of hotness remained the same, and I have no idea why.
这里,虽然 p
确实指向一个 Woman
和 hotness
的额外数据成员,但复制仍然使用 完成Person::operator=
,所以它不知道把额外的字段复制过来。有趣的是,它确实将内部指针复制到虚拟调度表,因此当您使用 p->Print()
时,它会调度到 Woman::Print
。
Woman* p = new Woman(20, 7);
p->Print();
*p = w;
p->Print();
20 and 7
copy assignment
copy assignment of woman
24 and 10Now the numbers seem to be right.
是的,因为编译器知道分配和复制Woman
的所有数据成员,其中包括指向虚拟调度表和hotness
的指针。
您的其余实验(删除显式定义的赋值运算符)表明,哪些成员被复制以及虚拟调度表指针是否/如何更新的问题是涉及的静态类型的基础,因此这些问题是有或没有你的实现。
So at this point I can't quite understand what the author meant to say, so if anyone could help me out, I'd appreciate it.
他的意思是,如果有人认为他们正在获取一个指针或对 Person
的引用并照原样复制它(就像您之前的尝试一样),他们通常会不小心删除派生类(Woman
) 相关成员并以一个简单的 Person
对象结束,在应用程序逻辑级别,Woman
是有意义的。通过删除这些运算符,编译器将防止这种意外的切片构造。正确的做法是提供一个 clone()
函数来创建一个新对象,无论动态对象类型是什么,允许一种“虚拟拷贝”。如果您搜索“克隆”,您会找到很多解释和示例。
关于C++ 为什么我应该抑制默认的复制构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22468067/
我正在尝试在Elasticsearch中返回的值中考虑地理位置的接近性。我希望近距离比某些字段(例如legal_name)重要,但比其他字段重要。 从文档看来,当前的方法是使用distance_fea
我是Elasticsearch的初学者,今天在进行“多与或”查询时遇到问题。 我有一个SQL查询,需要在Elastic中进行转换: WHERE host_id = 999 AND psh_pid =
智能指针应该/可以在函数中通过引用传递吗? 即: void foo(const std::weak_ptr& x) 最佳答案 当然你可以通过const&传递一个智能指针。 这样做也是有原因的: 如果接
我想执行与以下MYSQL查询等效的查询 SELECT http_user, http_req_method, dst dst_port count(*) as total FROM my_table
我用这两个查询进行测试 用must查询 { "size": 200, "from": 0, "query": { "bool": { "must": [ { "mat
我仍在研究 Pro Android 2 的简短服务示例(第 304 页)同样,服务示例由两个类组成:如下所示的 BackgroundService.java 和如下所示的 MainActivity.j
给定标记 like this : header really_wide_table..........................................
根据 shouldJS 上的文档网站我应该能够做到这一点: ''.should.be.empty(); ChaiJS网站没有使用 should 语法的示例,但它列出了 expect 并且上面的示例似乎
我在 Stack Overflow 上读到一些 C 函数是“过时的”或“应该避免”。你能给我一些这种功能的例子以及原因吗? 这些功能有哪些替代方案? 我们可以安全地使用它们 - 有什么好的做法吗? 最
在 C++11 中,可变参数模板允许使用任意数量的参数和省略号运算符 ... 调用函数。允许该可变参数函数对每个参数做一些事情,即使每个参数的事情不是一样的: template void dummy(
我在我从事的项目之一上将Shoulda与Test::Unit结合使用。我遇到的问题是我最近更改了此设置: class MyModel :update end 以前,我的(通过)测试看起来像这样: c
我该如何做 or使用 chai.should 进行测试? 例如就像是 total.should.equal(4).or.equal(5) 或者 total.should.equal.any(4,5)
如果您要将存储库 B 中的更改 merge 到存储库 A 中,是否应该 merge .hgtags 中的更改? 存储库 B 可能具有 A 中没有的标签 1.01、1.02、1.03。为什么要将这些 m
我正在尝试执行X AND(y OR z)的查询 我需要获得该代理为上市代理或卖方的所有已售属性(property)。 我只用 bool(boolean) 值就可以得到9324个结果。当我添加 bool
我要离开 this教程,尝试使用 Mocha、Supertest 和 Should.js 进行测试。 我有以下基本测试来通过 PUT 创建用户接受 header 中数据的端点。 describe('U
我正在尝试为 Web 应用程序编写一些 UI 测试,但有一些复杂的问题希望您能帮助我解决。 首先,该应用程序有两种模式。其中一种模式是“训练”,另一种是“现场”。在实时模式下,数据直接从我们的数据库中
我有一个规范: require 'spec_helper' # hmm... I need to include it here because if I include it inside desc
我正在尝试用这个测试我在 Rails 中的更新操作: context "on PUT to :update" do setup do @countdown = Factory(:count
我还没有找到合适的答案: onclick="..." 中是否应该转义 &(& 符号)? (或者就此而言,在每个 HTML 属性中?) 我已经尝试在 jsFiddle 和 W3C 的验证器上运行转义和非
import java.applet.*; import java.awt.*; import java.awt.event.*; public class Main extends Applet i
我是一名优秀的程序员,十分优秀!