Подтвердить что ты не робот

Почему защищенный конструктор вызывает ошибку в этом коде?

Один вопрос об защищенном конструкторе. Я узнал, что защищенный конструктор может использоваться в производном классе. Как бы то ни было, я обнаружил, что приведенный ниже код имеет ошибку. Почему так происходит?

class A
{
    protected:
        A(){}
};

class B: public A {
    public:
        B() {
            A* f=new A();           // Why it is not working here
        }
};
4b9b3361

Ответ 1

Это не имеет никакого отношения к конструкторам. Вот как работает protected доступ.

Как работает спецификатор доступа protected, он позволяет производному классу B получить доступ к содержимому объекта базового класса A только тогда, когда этот объект класса A является подобъектом класса B, Это означает, что единственное, что вы можете сделать в своем коде, - это получить доступ к содержимому A через B: вы можете получить доступ к элементам A через указатель типа B * (или ссылку типа B &). Но вы не можете получить доступ к тем же элементам с помощью указателя типа A * (или ссылки A &).

Рассмотрим следующий пример

class A {
protected:
  int i;
};

class B : A  {
  void foo() {
    i = 0;        // OK
    this->i = 0;  // OK

    B *pb = this;
    pb->i = 0;    // OK

    A *pa = this;
    pa->i = 0;    // ERROR

    ((A *) this)->i = 0; // ERROR
  }
};

В приведенном выше B::foo вы можете получить доступ к базовому элементу A::i, используя простой синтаксис i. Это эквивалентно использованию синтаксиса this->i. Оба будут работать, потому что указатель this имеет тип B *, т.е. Вы обращаетесь к A::i тщательно указателю типа B *. Это именно то, что должно разрешить спецификатор доступа protected. Доступ с помощью указателя pb работает по той же причине.

Однако, когда вы "конвертируете" this указатель на тип A *, вы больше не можете обращаться к A::i с помощью этого нового указателя, даже если вы все еще пытаетесь получить к нему доступ тот же самый член, что и раньше.

При применении к конструкторам спецификатор доступа protected имеет очень специфический эффект: защищенный конструктор может использоваться только для инициализации подобъектов базового класса. Он не может использоваться для инициализации автономных объектов (это то, что вы пытались сделать). Другими словами, защищенные конструкторы - это еще один способ реализовать концепцию абстрактного класса в С++ (наряду с чистыми виртуальными методами). Если конструкторы вашего класса защищены, то ваш класс является абстрактным. Вы не можете использовать его для определения независимых объектов "извне". (Конечно, вышесказанное не применяется в друзьях, а также внутри самого класса).

Ответ 2

Если базовый класс имеет защищенный конструктор, вы не можете создавать экземпляр класса напрямую. Но вы можете сделать это, чтобы вызвать конструктор из конструктора базового класса:

class A {

protected:
   A() {}
};

class B: public A {
public:
   B() : A() // allowed to access constructor like this
   {
      A* f = new A(); // Not allowed to access constructor like this!
   }
};

Прямой вызов конструктора, как показано ниже, дает следующую ошибку с gcc версии 4.1.2:

      A* f = new A(); // Not allowed to access constructor like this!

test.cpp:4: error: A::A() is protected

Однако этот вызов конструктору не вызывает ошибок:

   B() : A() // allowed to access constructor like this

Причина этого в том, что второй вызов обращается к конструктору A() через наследование, что разрешено. Однако он пытается явно создать новый экземпляр A(), вызвав конструктор напрямую:

      A* f = new A(); // Not allowed to access constructor like this!

Это может показаться неинтуитивным, так как B должен иметь доступ к конструктору, потому что B наследует от A. Однако, если вы объявите конструктор protected в С++, вы не сможете создать экземпляр этого класса, кроме как через наследование или дружеские отношения.

Ответ 3

Позвольте мне ответить следующим образом:

1) Конструкторы не получают Inherited, и поэтому в производном классе они не могут быть перегружены.
2) Конструкторы вызываются и не вызываются.
3) Если вы объявили простую функцию в say protected void print(), а затем попытались позвонить в B, это сработало бы. Это происходит bcoz, B унаследовал эту функцию.

4) Когда вы делаете что-то вроде этого b: a(), вы вызываете конструктор и разрешаете.
5) Попробуйте сделать B классом друзей класса A, а затем запустите и посмотрите, работает ли он.

Надеюсь, что это поможет.

Ответ 4

У меня был такой же вопрос, как и этот, и эта ссылка дает мне понять.

cppreference говорит вот так:

Protected members form the interface for the derived classes (which is   

distinct from the public interface of the class). 

A protected member of a class Base can only be accessed 

1) by the members and friends of Base 

2) by the members and friends (until C++17) of any class derived from Base, but only when operating on an object of a type that is derived from Base (including this)