Почему преобразование между производным* в базовое* не удается при частном наследовании?

Вот мой код -

#include<iostream>
using namespace std;

class base
{
public:
    void sid()
    {
    }  
};

class derived : private base
{
public:
    void sid()
    {
    }
};

int main()
{
    base * ptr;
    ptr = new derived; // error: 'base' is an inaccessible base of 'derived'
    ptr->sid();
    return 0;
}

Это дает ошибку времени компиляции.

error: 'base' is an inaccessible base of 'derived'

Поскольку компилятор попытается вызвать базовый класс sid(), почему я получаю эту ошибку? Может кто-нибудь объяснить это.


person Bruce    schedule 09.09.2010    source источник
comment
Вы не объявили метод virtual. Какую именно ошибку вы получаете?   -  person Dirk    schedule 09.09.2010
comment
В своем нынешнем виде это не имеет ничего общего с функцией sid(). Вы используете частное наследование, поэтому преобразование из derived* в base* не выполняется. Это то, о чем вы спрашиваете, или это как-то связано с методом sid()?   -  person Naveen    schedule 09.09.2010
comment
возможный дубликат защищенного производного класса   -  person kennytm    schedule 09.09.2010
comment
почему вы используете частное наследование вместо публичного?   -  person YeenFei    schedule 09.09.2010
comment
@Naveen: Да, это именно то, о чем я спрашиваю? Почему это не удается?   -  person Bruce    schedule 09.09.2010
comment
Какой смысл в пустом спецификаторе доступа private:? Зачем утечка памяти в простой программе? Либо delete, либо используйте auto_ptr.   -  person GManNickG    schedule 09.09.2010


Ответы (7)


$ 11,2 / 4 состояния-

Базовый класс B из N доступен в R, если

  • выдуманный публичный член B будет публичным членом N, или
  • R встречается у члена или друга класса N, а изобретенный публичный член B будет закрытым или защищенным членом N, или
  • R встречается у члена или друга класса P, производного от N, и изобретенный общедоступный член B будет закрытым или защищенным членом P, или
  • существует такой класс S, что B — базовый класс S, доступный в R, и S — базовый класс N, доступный в R».

Здесь «B» — «Основной», «N» — «Производный», а «R» — основной.

  1. Рассмотрим 2-й пункт: «R встречается у члена или друга класса N,...». Этот пункт не применяется, поскольку «R» (основной) не является ни членом, ни другом «N» (производного).

  2. Рассмотрим третий пункт: «R встречается у члена или друга класса P…». Этот пункт также не применяется по тем же причинам, что и выше.

  3. Рассмотрим 4-й пункт. Этот пункт снова не применяется.

Таким образом, мы можем заключить, что «база» не является доступным классом «производного».

$ 11,2 / 5 штатов -

Если базовый класс доступен, можно неявно преобразовать указатель на производный класс в указатель на этот базовый класс (4.10, 4.11). [Примечание: отсюда следует, что члены и друзья класса X могут неявно преобразовывать X* в указатель на закрытый или защищенный непосредственный базовый класс X. — конец примечания]

Поскольку Base не является доступным классом Derived при доступе в main, стандартное преобразование производного класса в базовый класс имеет неправильный формат. Отсюда ошибка.

РЕДАКТИРОВАТЬ 2:

Изучите сообщения об ошибках некоторых популярных компиляторов, и это должно помочь вам лучше понять. Обратите внимание, как часто и последовательно появляется слово «недоступный» во всех сообщениях об ошибках.

Ссылки взяты из проекта стандарта N3000. Я еще не скачал последнюю версию :)

GCC prog.cpp: в функции «int main()»: prog.cpp: 27: ошибка: «база» является недоступной базой «производного»

Comeau Online "ComeauTest.c", строка 26: ошибка: преобразование в недоступный базовый класс "base" не разрешено ptr = новый производный;

Ошибка VS2010 C2243: «приведение типа»: преобразование из «производного *» в «базовый *» существует, но недоступно

person Chubsdad    schedule 09.09.2010
comment
Не могли бы вы предоставить свою ссылку. - person Bruce; 09.09.2010
comment
@Bruce: Извините, я забыл упомянуть, что ссылки взяты из проекта стандарта N3000. Я обнаружил, что в C++03 есть несколько запутанных утверждений для понимания этой концепции. Я обновлю свой пост соответственно - person Chubsdad; 09.09.2010
comment
См. ответы Дугласа Лидера и ereOn для удобочитаемых и быстрых решений. - person mwjohnson; 07.01.2014

Я подозреваю, что проблема в том, что вы не можете преобразовать производный указатель в базовый указатель, поскольку наследование является частным.

person Douglas Leeder    schedule 09.09.2010
comment
Почему я не могу этого сделать? Какие проблемы с реализацией в этом? - person Bruce; 09.09.2010
comment
Частное наследование означает, что вы не хотите, чтобы интерфейс базового класса был доступен для другого кода, кроме кода дочернего класса. - person Klaim; 09.09.2010
comment
Мне действительно не хотелось тратить время на интерпретацию ответа Чубсдада, и это было именно то, что мне нужно было знать. Отсутствовал оператор public в моем определении производного класса. - person User; 12.07.2012

Chusbad предоставил подробное объяснение, касающееся стандарта, я постараюсь дать доступное объяснение.

В C++ есть 3 спецификатора уровня доступа: public, protected и private. Они предназначены для определения того, кто может получить доступ к методам, атрибутам или базовым классам. Это типично для объектно-ориентированных языков.

Здесь вы выбрали private наследование. Концептуально это означает, что вы пытаетесь СКРЫТЬ тот факт, что Derived наследует от Base посторонним, что обычно означает, что это детали реализации.

Как следствие, «внешнее» не знает об этой связи. Это обеспечивается компилятором с помощью этого сообщения inaccessible.

С точки зрения дизайна наследование private обычно не требуется. Либо применяется принцип замещения Лискова, и вы используете наследование public, либо это деталь реализации, и вы используете композицию.

person Matthieu M.    schedule 09.09.2010

Вы знаете, что class derived наследуется от class base, но функция main() этого не знает. Причина, по которой функция main() не знает об этом, заключается в том, что вы заставили class derived наследовать ЧАСТНО от class base.

Поэтому, когда вы пытаетесь присвоить new derived ptr, типы указателей несовместимы.

person Windows programmer    schedule 09.09.2010
comment
@WP: Не могли бы вы уточнить свой ответ? - person Bruce; 09.09.2010

Попробуй это:

#include<iostream>
#include<conio.h>
using namespace std;

class base
{
      private:
      public:
          virtual void sid() // You might want to declare sid virtual
             {
                  cout<<"base";
             } 
          virtual ~base() // You then probably need a virtual destructor as well.
             {
             } 
};

class derived : public base //public inheritance
{
      private:
      public:
             void sid()
             {
                  cout<<"derived";
             }
};

int main()
{
    base * ptr;
    ptr = new derived;
    ptr->sid();
    getch();
    return 0;
}
person ereOn    schedule 09.09.2010
comment
Вы имели в виду virtual void sid()? Также вам нужно, чтобы деструктор базового класса был virtual. - person Naveen; 09.09.2010
comment
@Naveen: Спасибо. Я собирался добавить деструктор ;) Также да, private была опечаткой. - person ereOn; 09.09.2010
comment
Виртуальный деструктор - хорошая идея. Включение виртуальной функции sid противоречит заявленной цели оригинального плаката. - person Windows programmer; 09.09.2010

это дает ошибку C2243: «приведение типа»: преобразование из «производного *» в «базовый *» существует, но недоступно. Этот производный класс был унаследован частным образом. Поэтому объект базового класса не создается, когда происходит создание производного получения. для создания производного объекта первые вызовы идут на создание объекта базового класса, чего не происходит. Решение состоит в том, чтобы вывести класс публично. не имеет значения, используете ли вы виртуальное ключевое слово с функциями-членами или нет.

person Santosh kumar    schedule 09.09.2010

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

person Alexander Rafferty    schedule 09.09.2010
comment
Знаете, я НЕНАВИЖУ, когда люди голосуют против и не оставляют комментарии. - person Alexander Rafferty; 09.09.2010
comment
Я не проголосовал за этот ответ, но я думаю, что это ошибочно. Я видел, как компиляторы выдавали предупреждения о сокрытии функции базового класса функцией производного класса, но никогда не сообщали об ошибке. - person Head Geek; 16.10.2011