Вектор объекта класса с приватным конструктором и деструктором? - PullRequest
0 голосов
/ 19 февраля 2020

Определяя классы A с помощью закрытого конструктора и деструктора (так и должно быть!) И B как дружественного класса, как я могу создать вектор объектов A в B и заполнить его функцией 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;
}

Ответы [ 2 ]

1 голос
/ 19 февраля 2020

как я могу создать вектор объектов A в B [...]?

Вы не можете этого сделать. В то время как B является friend из A, std::vector является , а не a friend из A, что означает, что он не может получить доступ к private членам A, например , конструктор, который необходим для работы вектора.

Однако, если у вас все в порядке с небольшим косвенным обращением, небольшим потенциальным падением производительности и изменением вашей подписи, вы можете заменить нерабочий std::vector<A> с рабочим std::vector<std::unique_ptr<A, deleter>>.

Важно отметить, что обычный std::unique_ptr здесь не будет работать. У него есть проблема, аналогичная std::vector - он не может получить доступ к private деструктору A. Один из способов обойти это - передать всю работу по созданию и уничтожению A с полностью на 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 с.

Полный 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}
    });
}
0 голосов
/ 19 февраля 2020

Хотя @ Fureei sh имеет изящное решение, вот несколько более простая альтернатива: просто оберните его.

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 и вот вам go. По сути, вы можете трактовать AccessPrivate почти как настоящий частный класс, только один уровень косвенности.

...