我有以下情况:类NoEntry包含外界可以检查的数据,但外界不允许以任何方式创建这些对象。这样的类看起来像这样:
#ifndef INCLUDED_NOENTRY_
#define INCLUDED_NOENTRY_
#include <string>
class NoEntry
{
std::string d_name;
size_t d_area = 0;
size_t d_date = 0;
public:
std::string const &name() const;
size_t area() const;
size_t date() const;
private:
NoEntry(NoEntry const &other) = default;
NoEntry() = default;
NoEntry(std::string const &name, size_t area, size_t date);
};
#endif
使用 NoEntry 对象是某些类的特权,这些类被声明为 NoEntry 的友元。所以该类包含友元声明:
#ifndef INCLUDED_NOENTRY_
#define INCLUDED_NOENTRY_
#include <string>
class NoEntry
{
friend class PrivilegedOne;
friend class PrivilegedTwo;
std::string d_name;
size_t d_area = 0;
size_t d_date = 0;
public:
std::string const &name() const;
size_t area() const;
size_t date() const;
private:
NoEntry(NoEntry const &other) = default;
NoEntry() = default;
NoEntry(std::string const &name, size_t area, size_t date);
};
#endif
我设计了以下 PrivilegedOne 界面:
#ifndef INCLUDED_PRIVILEGEDONE_
#define INCLUDED_PRIVILEGEDONE_
#include <iosfwd>
#include <vector>
#include "../noentry/noentry.h"
class PrivilegedOne
{
std::vector<NoEntry> d_noEntry;
public:
PrivilegedOne(std::string const &fname);
private:
NoEntry nextEntry(std::istream &in); // empty name: all were read
};
#endif
它的成员nextEntry是一个简单的成员:它从文件中读取数据,并返回一个NoEntry对象。
//#define XERR
#include "privilegedone.ih"
NoEntry PrivilegedOne::nextEntry(istream &in)
{
NoEntry ret;
in >> ret.d_name >> ret.d_area >> ret.d_date;
if (not in) // no more NoEntries: ensure
ret.d_name.clear(); // that d_name is empty
return ret;
}
PrvilegedOne 的构造函数必须读取所有 NoEntry 对象,并且必须将它们存储在 d_noEntry 中。这是它的原始实现:
//#define XERR
#include "privilegedone.ih"
PrivilegedOne::PrivilegedOne(string const &fname)
{
ifstream in{ fname };
while (true)
{
NoEntry next = nextEntry(in);
if (next.name().empty())
break;
d_noEntry.push_back(next); // Not working
}
}
“Notworking”注释是导致所有问题的行。
为什么该语句没有发挥其作用? 不修改 NoEntry 类中的任何内容,而仅关注 PrivilegedOne:必须做什么才能允许此类的对象在其 d_noEntry vector 中存储 NoEntry 对象?
我想我应该重新设计d_noEntry的定义。然后我只需修改带有“不工作”注释的行即可。
但我不知道如何。
最佳答案
作为@“n.1.8e9-where's-my-share m.”评论说,您无法创建可与任何可能的实现一起使用的这种类型的 std::vector。
push_back() method of std::vector接受引用,但需要将对象复制到新位置。
您可以做的是创建一个包装器和 friend class
它。
实现该类如下:
#pragma once
#include "NoEntry.h"
class NoEntryWrapper {
NoEntry content;
friend class NoEntry;
public:
NoEntryWrapper() = default;
NoEntryWrapper(const NoEntryWrapper &) = default;
NoEntryWrapper(const NoEntry & content) : content(content) {}
NoEntry &getContent() { return content; }
};
修改NoEntry
实现:
// do not include "NoEntryWrapper.h"
class NoEntryWrapper; // forward declare it
class NoEntry
{
friend class PrivilegedOne;
friend class PrivilegedTwo;
friend class NoEntryWrapper; // this is new
// ... your original code ...
NoEntry(const NoEntryWrapper &wrapper);
// make NoEntryWrapper implicitly convertable back to NoEntry
}
并在 .cpp
中定义新添加的构造函数文件
#include "NoEntryWrapper.h"
NoEntry::NoEntry(const NoEntryWrapper &wrapper) : NoEntry(wrapper.content) {}
并且还修改PrivilegedOne
类:
替换std::vector<NoEntry> d_noEntry;
与 std::vector<NoEntryWrapper> d_noEntry;
.
您现在可以使用该 vector ,就像您所异常(exception)的那样。
示例代码:
std::vector<NoEntryWrapper> d_noEntry;
d_noEntry.push_back(NoEntry("test", 0, 1));
NoEntry test = d_noEntry[0];
std::cout << test.d_name << " " << test.d_area << std::endl;
d_noEntry[0] = NoEntry("other", 5, 5);
d_noEntry[0].getContent().d_name = "other (name changed)";
// this is the only drawback - you need a getter to access it this way
NoEntry other = d_noEntry[0];
std::cout << other.d_name << " " << other.d_area << std::endl;
// Output:
//test 0
//other (name changed) 5
关于c++ - 带私有(private)构造函数的 vector <class>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70434845/