C++ 中的拷贝控制
一般来说进行资源管理的类都需要对拷贝过程进行控制,另外在类需要进行某些记录操作时 也需要进行拷贝控制。以博客生成为例,一篇博客可能具有多个标签,而一个标签下面也会 管理多篇博客。
0.1 Tag
类的实现
#include <set>
#include <string>
#include <iostream>
class Blog;
class Tag {
friend class Blog;
friend std::ostream& operator<<(std::ostream& os, Tag const& tag);
public:
Tag(std::string const& __name = "") : name(__name) { }
void add(Blog*);
void remove(Blog*);
std::string const& get_name() { return name; }
private:
std::string name; // 标签的名字
std::set<Blog*> blogs; // 属于此标签的 Blog
};
void Tag::add(Blog* blog)
{
blogs.insert(blog);
}
void Tag::remove(Blog* blog)
{
blogs.erase(blog);
}
0.2 Blog
类的实现
#include <iostream>
#include <string>
#include <set>
class Tag;
class Blog {
friend class Tag;
friend std::ostream& operator<<(std::ostream& os, Blog const& blog);
public:
Blog(std::string const& __content = "") : content(__content) { }
// 拷贝控制成员函数
Blog(Blog const&); // 拷贝构造
Blog& operator=(Blog const&); // 拷贝赋值
~Blog(); // 析构
// 从给定的 Tag 中添加或删除本 Blog
void add_to(Tag&);
void remove_from(Tag&);
std::string const& get_content() { return content; }
private:
std::string content; // Blog 的内容
std::set<Tag*> tags; // 本 Blog 的 tags,被隐式初始化为空集合
void add_to_tags(Blog const&); // 将本 Blog 添加到参数 Blog 的所有 Tag 中
void remove_from_tags(); // 从 tags 中的每个 Tag 中删除本 Blog
};
void Blog::add_to(Tag& tag)
{
tags.insert(&tag);
tag.add(this);
}
void Blog::remove_from(Tag& tag)
{
tags.erase(&tag);
tag.remove(this);
}
void Blog::add_to_tags(Blog const& blog)
{
for (auto tag : blog.tags)
tag->add(this);
}
void Blog::remove_from_tags()
{
for (auto tag : tags)
tag->remove(this);
}
Blog::Blog(Blog const& blog) : content(blog.content), tags(blog.tags)
{
add_to_tags(blog);
}
Blog::~Blog()
{
remove_from_tags();
}
Blog& Blog::operator=(Blog const& blog)
{
// 先将本 Blog 从原来的 tags 中删除,再加入到 blog 参数的 tags 列表中,从而处
// 理自赋值情况
remove_from_tags();
content = blog.content;
tags = blog.tags;
add_to_tags(blog);
return *this;
}
0.3 测试我们的 Blog
和 Tag
类
#include <fmt/core.h>
<<Tag-class>>
<<Blog-class>>
std::ostream& operator<<(std::ostream& os, Tag const& tag)
{
os << fmt::format("Tag({0}) has {1} blogs:\n", tag.name, tag.blogs.size());
std::set<Blog*>::size_type index = 0;
std::set<Blog*>::const_iterator iter = tag.blogs.cbegin();
for (; index < tag.blogs.size(); ++index, ++iter) {
os << fmt::format("[{0}] ", index + 1) << (*iter)->get_content() << std::endl;
}
return os;
}
std::ostream& operator<<(std::ostream& os, Blog const& blog)
{
os << fmt::format("Blog({0}) has {1} tags: ", blog.content, blog.tags.size());
std::set<Tag*>::size_type index = 0;
std::set<Tag*>::const_iterator iter = blog.tags.cbegin();
for (; index < blog.tags.size() - 1; ++index, ++iter)
os << (*iter)->get_name() << ", ";
return os << (*iter)->get_name() << "." << std::endl;
}
int main()
{
Tag python("Python"), cpp("C++"), program("Program languages");
Blog b1("Python is elegant.");
Blog b2("Python is simple.");
Blog b3("C++ is evil.");
b1.add_to(python);
b2.add_to(python);
b3.add_to(cpp);
b1.add_to(program);
b2.add_to(program);
b3.add_to(program);
std::cout << python << std::endl;
std::cout << cpp << std::endl;
std::cout << program << std::endl;
// 从 b3 拷贝构造 b4
Blog b4(b3);
std::cout << cpp << std::endl;
std::cout << b4 << std::endl;
b4 = b1;
std::cout << cpp << std::endl;
std::cout << python << std::endl;
std::cout << b4 << std::endl;
}
Tag(Python) has 2 blogs: [1] Python is elegant. [2] Python is simple. Tag(C++) has 1 blogs: [1] C++ is evil. Tag(Program languages) has 3 blogs: [1] Python is elegant. [2] Python is simple. [3] C++ is evil. Tag(C++) has 2 blogs: [1] C++ is evil. [2] C++ is evil. Blog(C++ is evil.) has 2 tags: C++, Program languages. Tag(C++) has 1 blogs: [1] C++ is evil. Tag(Python) has 3 blogs: [1] Python is elegant. [2] Python is simple. [3] Python is elegant. Blog(Python is elegant.) has 2 tags: Python, Program languages.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: C++ Playground
下一篇: fcitx 输入法配置
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论