具有私有构造函数和析构函数的类对象的向量?
Posted
技术标签:
【中文标题】具有私有构造函数和析构函数的类对象的向量?【英文标题】:Vector of class object with private constructor and destructor? 【发布时间】:2020-02-19 12:29:19 【问题描述】:使用私有构造函数和析构函数定义类 A(应该是这样!)和 B 作为友元类,我如何在 B 中创建 A 对象的向量并用函数 addA() 填充它。我收到错误“错误 C2248:“A::~A”:无法访问在 A 类中声明的私有成员”。
class A
private:
A();
A(const std::string& name, const float& num);
~A();
public:
friend class B;
private:
std::string name_;
float num_;
;
A::A()
name_ = "NoName";
num_ = 0.0;
A::A(const std::string& name, const float& num)
name_ = name;
num_ = num;
A::~A()
class B
public:
B();
~B();
void addA(const std::string name, const float num);
private:
vector<A> vecA;
;
B::B()
B::~B()
void B::addA(const std::string name, const float num)
A a(name, num);
vecA.push_back(a);
int main()
B b;
b.addA("Name", 1.0);
return 0;
【问题讨论】:
只是出于好奇;为什么你会想要一个私有析构函数? 为什么你的构造函数和析构函数都是private
?
虽然B
是A
的朋友,但std::vector<A>
不是是A
的朋友,因此无法访问@987654328 的私人成员@。就像它需要的析构函数,因为它内部生命周期处理它存储的对象。
@Clearer What is the use of having destructor as private?
我相信您可以创建指向 A 的指针向量,而不是指向 A 的对象向量。但是当您在向量中添加或删除项目时,您必须处理内存。
【参考方案1】:
如何在 B [...] 中创建 A 对象的向量?
你不能那样做。虽然B
是A
的friend
,但std::vector
不是 A
的friend
,这意味着它无法访问private
的A
成员,例如,构造函数,它是向量工作所必需的。
但是,如果您可以接受一点间接性、潜在的性能影响和签名更改,您可以将不工作的std::vector<A>
替换为工作std::vector<std::unique_ptr<A, deleter>>
。
请务必注意,普通的std::unique_ptr
在这里不起作用。它与std::vector
有类似的问题——它无法访问A
的private
析构函数。解决此问题的一种方法是将构建和销毁 A
s 的工作完全外包给 B
- 通过显式构建和销毁,即:
new A(name, num)
static void deleter_a(A* a) delete a;
在B
的范围内。
现在我们可以这样做了:
std::vector<std::unique_ptr<A, std::function<void(A*)>>> vecA;
而不是:std::vector<A>
或 std::vector<std::unique_ptr<A>>
。这很重要——std::unique_ptr
和 std::vector
都不会构造或破坏你的A
s。 B
完全负责构造 (new A(name, num)
) 和销毁 (static void deleter_a(A* a) delete a;
) A
s。
完整的B
类:
class B
public:
B() ; // or = default
~B() ; // or = default
void addA(const std::string name, const float num);
private:
static void deleter_a(A* a) delete a;
using deleter_a_t = void(A*);
std::vector<std::unique_ptr<A, std::function<deleter_a_t>>> vecA;
;
void B::addA(const std::string name, const float num)
vecA.push_back(std::unique_ptr<A, std::function<deleter_a_t>>
new A(name, num), std::function<deleter_a_t>deleter_a
);
【讨论】:
你是对的!您认为“vector > VecA”可能有帮助吗?如果是这样,我怎么能用对象填充它!或者您建议用于存储 A 对象的其他容器而不是矢量,它可以在这里工作?这些问题可能很幼稚,但我是 C++ 新手! ;) 不。这需要std::shared_pointer<A>
成为A
的朋友。考虑给A
公共构造函数和析构函数。您目前对具有私有构造函数和析构函数的类存在矛盾,同时希望像使用它们一样具有公共构造函数和析构函数。编译器必须拒绝这种矛盾 - 因为通过将事物声明为私有,您已经告诉它这样做。
@Hossein std::shared_ptr<A>
也会有同样的问题 - 它不能使用 private
成员,在这种情况下,它们是构造和破坏对象所必需的。但是,我正在编辑问题以使其正常工作。
@Hossein 没问题,乐于助人。如果上述解决方案解决了您的问题,请考虑通过单击分数下方的勾号来接受此答案,以便告知未来访问者您的问题该解决方案确实解决了问题。【参考方案2】:
虽然@Fureeish 有一个简洁的解决方案,但这里有一个稍微简单的替代方案:只需将其包装起来。
class AccessPrivate;
class PrivStuff
private:
PrivStuff()
~PrivStuff()
public:
friend class AccessPrivate;
std::string m_data;
;
class AccessPrivate
public:
AccessPrivate() = default;
~AccessPrivate() = default;
PrivStuff m_priv;
;
int main(int argc, char* argv[])
std::vector<AccessPrivate> myvec;
myvec.resize(4);
for (auto& stuff : myvec)
stuff.m_priv.m_data = "heya";
如果您需要更复杂的东西,例如传入参数,只需将等效的构造函数添加到 AccessPrivate
即可。您基本上可以将AccessPrivate
视为几乎就像实际的私有类一样,只是一级间接。
【讨论】:
我采用了@Fureeish 的想法!顺便谢谢你:) 这个答案要好得多,它没有引入非常复杂的间接,更不用说unique_ptr
的弹坑性能了!以上是关于具有私有构造函数和析构函数的类对象的向量?的主要内容,如果未能解决你的问题,请参考以下文章