Избавление от ошибки C2243

можно ли избавиться от ошибка C2243?

class B {};
class D : protected B {};

D d;
B *p = &d;   // conversion from 'D *' to 'B &' exists, but is inaccessible

у меня была эта ошибка в моем приложении, и в конце мне удалось скомпилировать ее, сделав явное преобразование:

D d;
B *p = (B*)&d;

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

Я попытался избежать явного преобразования, создав оператор B () в классе D, чтобы сделать преобразование доступно:

class B {};
class D : protected B 
{
 public:
 operator B() {return *this;}
};

но нет так нет.

любое другое решение, чтобы избежать явного преобразования?

6 ответов


Если вы хотите разрешить преобразование, вы должны использовать открытое наследование.

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

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


, потому что protected и private наследование не is-a отношения, они просто синтаксический сахар для композиции. Ваши классы могут быть переписаны точно так же, но вы теряете удобство, позволяя компилятору определить b для вас, и используя B членов непосредственно вместо того, чтобы ссылаться на него явно:

class D
{
  protected:
  B b;
};

для второго пункта вашего вопроса:

operator B() {return *this;}

эта строка имеет отношение к B и D. D* и B* полностью отличается от B и D, хотя они являются указателями на них! чтобы привести указатели, вы можете переинтерпретировать указатель:

B *p = reinterpret_cast<B*>(&d); // TOTALLY WRONG, although it compiles :)

не выше линии! Я думаю, вы могли бы дать нам больше информации о что вы пытаетесь достичь.


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

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

Если вы хотите иметь неявное преобразование из ваших детей, вам нужно сделать его общедоступным для всех, чтобы знать.


проблема здесь заключается в том, что вы пытаетесь сделать за информация скрывается, что защищенный обеспечивает. Если вы хотите получить доступ к экземпляру D как B, почему вы унаследовали его как защищенный, а не общедоступный?. При использовании защищенного наследования вы хотите, чтобы только экземпляры D и его потомки знали о компоненте B. Вам нужно еще раз взглянуть на то, чего вы хотите достичь.

старый стиль C бросил, что вы используете не имеет ни одной тонкости новых c++ приведений, поэтому он дает вам код, который будет компилироваться, но проблема действительно в наследовании.


вы пытались сделать оператор B() общедоступным в классе D? В коде, который вы показали, он будет помечен как защищенный и все еще недоступный. Но я бы избегал операторов преобразования в целом, если это возможно.

по-прежнему, наследование защищено Б означает, что вы намерены запретить делать б* р = &р. Представьте, если б был на самом деле защищенную переменную-член в верхней части д. Так как вы не сможете получить доступ д. б в таком случае, вы не можете получить доступ к D как Б*, если вы разыгрываете его.

Так что либо наследуйте B публично или используйте свои слепки. Я бы пошел с наследованием B публично, потому что наследование его защищено в основном говорит:" Не используйте меня как B", что вы все равно пытаетесь сделать.


поскольку никто снаружи не знает, что они являются родительскими, вы можете выполнить это действие только в производном классе D.Это пример (тест в Visual Studio 2013):

class BASE{};

class BASE1 :protected BASE{};

class BASE2 :protected BASE1
{
public:
    void func(BASE &a, BASE1 &b){a = b;}
};

void main()
{
    BASE a;
    BASE1 b;
    BASE2 c;

    c.func(a, b);;
    system("pause");
 }