具有私有构造函数和析构函数的类对象的向量?

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 虽然BA 的朋友,但std::vector&lt;A&gt;不是A 的朋友,因此无法访问@987654328 的私人成员@。就像它需要的析构函数,因为它内部生命周期处理它存储的对象。 @Clearer What is the use of having destructor as private? 我相信您可以创建指向 A 的指针向量,而不是指向 A 的对象向量。但是当您在向量中添加或删除项目时,您必须处理内存。 【参考方案1】:

如何在 B [...] 中创建 A 对象的向量?

你不能那样做。虽然BAfriend,但std::vector 不是 Afriend,这意味着它无法访问privateA 成员,例如,构造函数,它是向量工作所必需的。

但是,如果您可以接受一点间接性、潜在的性能影响和签名更改,您可以将不工作的std::vector&lt;A&gt; 替换为工作std::vector&lt;std::unique_ptr&lt;A, deleter&gt;&gt;

请务必注意,普通的std::unique_ptr 在这里不起作用。它与std::vector 有类似的问题——它无法访问Aprivate 析构函数。解决此问题的一种方法是将构建和销毁 As 的工作完全外包给 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&lt;A&gt;std::vector&lt;std::unique_ptr&lt;A&gt;&gt;。这很重要——std::unique_ptrstd::vector 都不会构造破坏你的As。 B 完全负责构造 (new A(name, num)) 和销毁 (static void deleter_a(A* a) delete a; ) As。

完整的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&lt;A&gt; 成为A 的朋友。考虑给A公共构造函数和析构函数。您目前对具有私有构造函数和析构函数的类存在矛盾,同时希望像使用它们一样具有公共构造函数和析构函数。编译器必须拒绝这种矛盾 - 因为通过将事物声明为私有,您已经告诉它这样做。 @Hossein std::shared_ptr&lt;A&gt; 也会有同样的问题 - 它不能使用 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的弹坑性能了!

以上是关于具有私有构造函数和析构函数的类对象的向量?的主要内容,如果未能解决你的问题,请参考以下文章

PHP构造函数和析构函数

构造函数和析构函数

构造函数和析构函数的区别

PHP 构造函数和析构函数

php构造函数和析构函数

PHP构造函数和析构函数