C ++ размещает объекты в куче базового класса с помощью защищенных конструкторов через наследование - PullRequest
6 голосов
/ 25 декабря 2010

У меня есть класс с защищенным конструктором:

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

Теперь я унаследовал его и определил две статические функции, и мне удалось фактически создать объекты класса B, но не в куче:*

class A : public B {
public:
    static B createOnStack() {return B();}
    //static B* createOnHeap() {return new B;} //Compile time Error on VS2010
};

B b = A::createOnStack(); //This works on VS2010!

Вопрос в следующем: 1) Является ли VS2010 неправильным в разрешении первого случая?2) Можно ли создавать объекты B без изменения B каким-либо образом (без дружбы и без дополнительных функций).Я спрашиваю, потому что возможно сделать что-то подобное при работе с экземплярами B и его функциями-членами, см .: http://accu.org/index.php/journals/296

Заранее благодарен за любое предложение!

Ответы [ 2 ]

5 голосов
/ 25 декабря 2010
  1. Да, этот код не соответствует. Это связано со специальными правилами для защищенного доступа членов (черновик C ++ 03, 11.5 / 1):

    Когда друг или функция-член производного класса ссылается на защищенную нестатическую функцию-член или защищенный нестатический элемент данных базового класса, проверка доступа применяется в дополнение к описанным ранее в пункте 11.10). За исключением случаев формирования указателя на член (5.3.1), доступ должен осуществляться через указатель, ссылку или объект самого производного класса (или любого класса, производного от этого класса) (5.2.5).

    Когда вы используете B () или новую B (), вы эффективно используете конструктор через указатель на базовый класс.

  2. Вы можете создать объект типа A (я предполагаю, что A такой же, как отправленный - без дополнительных членов / нестатических функций) и использовать его вместо этого. Если вы создаете его в стеке, все должно работать нормально, если только вы не пытаетесь присвоить ему другие объекты типа B. Если вы создаете его в куче, все в порядке, пока деструктор B виртуален. Если деструктор B не является виртуальным, и вы возвращаете новый A () как B *, то удаление указателя является технически неопределенным поведением (5.3.5 / 3:

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

    Однако на практике вы, вероятно, найдете его работающим нормально, поэтому вы можете положиться на реальное поведение, если другого обходного пути нет (т. Е. Используйте его как последнее средство).

2 голосов
/ 25 декабря 2010

Существует общее недопонимание того, что на самом деле означает protected.Это означает, что производный класс может обращаться к этому конкретному члену на самой , а не на других объектах.Компилятор должен был отклонить обе функции, так как в обоих случаях он обращается к конструктору объекта, который не относится к производному типу.

Другой пример, который проще обсудить на предмет его правильности, будет:*

Закомментированная строка является ошибкой, поскольку она пытается изменить объект типа base, не обязательно объект derived.Если бы язык позволил скомпилировать этот код, вы могли бы изменить объект типа base или даже объекты типов derived1, derived2 ..., эффективно нарушая правила доступа.

struct derived2 : base {};
int main() {
   base b;
   derived2 d;
   derived::modify( b );    // modifying a base!!!
   derived::modify( d );    // modifying a derived2!!!
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...