2015-09-22 4 views
1

Код ниже - это упрощенная версия того, с чем я работал сегодня. Он имеет 2 класса A и B. Класс B пытается использовать частный конструктор класса A, но он терпит неудачу. Если я создаю конструктор публично, код компилируется отлично. Почему?класс друга не может вызвать частный конструктор

#include <vector> 

class A 
{ 
friend class B; 
private: 
    A(int * int_ptr) { 
     m_int = *int_ptr; 
    } 
private: 
    int m_int; 
}; 


class B 
{ 
friend class A; 
public: 
    static void create_vec_a() { 
     int v1(1); 
     int v2(2); 

     std::vector<int *> int_ptr_vec{ 
      &v1, 
      &v2 
     }; 

     std::vector<A> a_vec(int_ptr_vec.begin(), 
      int_ptr_vec.end()); 
    } 
}; 

int main(int argc, char *argv[]) 
{ 
    B::create_vec_a(); 
    return 0; 
} 

Я получаю ошибку в Visual Studio является:

'A::A': cannot access private member declared in class 'A' 

На Clang:

test.cpp:28:18: note: in instantiation of function template specialization 'std::vector<A, std::allocator<A> >::vector<__gnu_cxx::__normal_iterator<int **, std::vector<int *, std::allocator<int *> > >, void>' requested here 
      std::vector<A> a_vec(int_ptr_vec.begin(), 
         ^
test.cpp:7:2: note: declared private here 
    A(int * int_ptr) { 
    ^

ответ

3

Вы должны были бы друг std::allocator<A>;, потому что кто-то пытается получить доступ к конструктору.

class A 
{ 
    friend class std::allocator<A>; 
... 

Трудно прокомментировать общий дизайн, хотя из данного образца, но я считал бы просто сделать его публичным, потому что любой, кто может видеть class A можно построить его, если СТЛ может.

-1

Попробуйте использовать друг A :: A (INT * INT_PTR) в классе В.

0

лязга выходы ошибок на самом деле очень описательный характер. Вызов std::vector<A> a_vec(int_ptr_vec.begin(), int_ptr_vec.end()); бы вызвать конструктор, который может быть реализован (очень наивно), как-то, что выглядит следующим образом:

vector(TIterator _Begin, TIterator _End) { 
    for (auto it = _Begin; it < _End; ++it) { 
    this->push_back(T(*it)); // This calls the constructor you have marked as private 
    } 
} 

Поскольку требуется конструктор в классе помечен как личный, нет никакого способа для компиляции, чтобы добиться успеха, когда это конкретная функция расширяется путем прохождения шаблона вашего компилятора.

Отметить, что конструктор общественности - это правильная вещь здесь (он - публично используется в конце концов).

В качестве альтернативы вы можете оставить конструктор закрытым и вручную заполнить вектор каким-либо другим способом после его создания. Компиляция не сработает, потому что код шаблона, требующий конструктора, не будет создан. Что-то вроде:

std::vector<A> a_vec; 
for (auto ptr: int_ptr_vec) { 
    a_vec.push_back(A::create(ptr)); // Define create() in A as you wish 
} 
1

Фактический вызов конструктора A происходит в std::allocator<A>::construct, а не в пределах B, так что вам нужно будет std::allocator<A> быть другом. Однако это позволит каждому вызвать ваш частный конструктор, что, вероятно, нежелательно.

Самый простой подход (который не предполагает создание публичного или эффективного публичного конструктора A), просто должен был построить A в пределах B и переместить их в вектор. (The A вы показали неявно объявлены копировать и перемещать конструкторы.)

std::vector<A> a_vec; 
for (int* p : int_ptr_vec) { 
    a_vec.push_back(A(p)); 
} 

Если A не предназначен, чтобы быть подвижными (редко, но это может произойти, если он содержит, скажем, атомные переменное или семафор как член), то вы можете рассмотреть более сложные методы контроля доступа, такие как требование передачи специального маркера в конструктор.

class A 
{ 
public: 
    class Token 
    { 
     friend class B; 
    private: 
     Token() {} 
    }; 
    A(Token, int * int_ptr) { 
     m_int = *int_ptr; 
    } 
private: 
    int m_int; 
}; 

// ... 
// inside B 
std::vector<A> a_vec; 
for (int* p : int_ptr_vec) { 
    a_vec.emplace_back(A::Token(), p); 
} 

(Этот подход также может быть использован в более общем плане, например, , на языках без дружбы, таких как Java.)

Смежные вопросы