Ответ 1
Вы можете сделать конструктор Base
закрытым и иметь эти два класса друзей, например.
#include <iostream>
class Base
{
private:
Base() {}
friend class Derived1;
friend class Derived2;
};
class Derived1 : public Base
{
};
class Derived2 : public Base
{
};
int main() {
Derived1 obj;
Base obj2; // Error
return 0;
}
Также обратите внимание: copy/move конструктор базового класса должен также быть закрытым. Я не добавляю код, чтобы сосредоточиться на основном предложении, но вы тоже должны подумать об этом.
Изменить в отношении конструкторов друзей.
Во-первых: вы не можете ссылаться на элементы неполного типа до того, как его определение увидит компилятор (он работает как одноразовый проход, и может быть связано какое-то разрешение перегрузки). Это означает, что следующее не будет работать:
class Derived1;
class Derived2;
class Base
{
private:
Base() {}
friend Derived1::Derived1(); // Error - incomplete type 'Derived1' in nested name specifier
};
class Derived1 : public Base
{
public:
Derived1() {};
};
...
и вы не можете перенаправить объявление базового класса (вы не знаете, сколько места выделяется для производного объекта):
class Base;
class Derived1 : public Base // Error: base class has incomplete type
{
public:
Derived1() {};
};
class Base
{
private:
Base() {}
friend Derived1::Derived1();
};
...
поэтому в вашем конкретном случае вам лучше с доступом к классу друзей, если вы не хотите что-то изменить в своем дизайне.