Отървете се от грешка 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;}
};

Но няма начин.

Някакво друго решение за избягване на изрично преобразуване?


person Lucas Ayala    schedule 24.09.2009    source източник


Отговори (6)


Ако искате да разрешите преобразуване, трябва да използвате публично наследяване.

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

Трябва да разглеждате непубличното наследяване само като форма на композиция с добавена възможност за замяна на методи.

person Paolo Tedesco    schedule 24.09.2009
comment
Какво ще кажете за предоставяне на достъп само до const интерфейса на базовия клас? Така че частно наследяване и разрешаване на прехвърляне към const base&? Питам, защото не мога да го накарам да работи на MSVC... - person S. Paris; 07.04.2017
comment
Просто отговарям на себе си, трябва да управлявате класа чрез агрегиране, а не чрез наследяване, в противен случай MSVC се обърква и се опитва да реши преобразуването чрез частно наследяване (скриване на cast оператор) - person S. Paris; 07.04.2017

Тъй като 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 :)

Не правете горния ред! Мисля, че можете да ни дадете повече информация за това, което се опитвате да постигнете.

person AraK    schedule 24.09.2009

Тъй като от D и Ds деца, никой не знае, че те са родител-дете, така че трябва да го направите изрично.

Ето какво означава защитено наследство, само вашето семейство (деца) ще знаят, че наследявате. И бихте могли да го използвате, например в метод за деца, там имплицитното преобразуване би било законно.

Ако искате да имате имплицитно преобразуване от вашите деца, трябва да го направите публично достояние, за да го знаят всички.

person Arkaitz Jimenez    schedule 24.09.2009

Проблемът тук е, че се опитвате да направите краен обход около скриването на информацията, което предоставя атрибутът protected. Ако искате да получите достъп до екземпляр на D като B, защо сте го наследили като защитен, а не публичен?. Това, което казвате при използването на защитено наследяване, е, че желаете само екземпляри на D и неговите потомци да знаят за B компонента. Трябва да погледнете отново какво искате да постигнете.

Старият стил C, който използвате, няма нищо от тънкостите на по-новите C++, така че ви дава код, който ще се компилира, но проблемът всъщност е в наследяването.

person Tim Allman    schedule 24.09.2009

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

И все пак, наследяването на защитен B означава, че възнамерявате да предотвратите извършването на B* p = &d. Представете си, че B действително беше защитена членска променлива в горната част на D. Точно както нямате достъп до D.b в този случай, не можете да получите достъп до d като B*, освен ако не го изхвърлите.

Така че или наследете B публично, или използвайте вашите отливки. Бих се съгласил с публичното наследяване на B, защото наследяването му защитено основно казва „Не ме използвайте като B“, което вие така или иначе се опитвате да направите.

person AshleysBrain    schedule 24.09.2009

Тъй като никой отвън не знае, че е родител-дете, вие можете да извършите това действие само в производния на 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");
 }
person Jean Leo    schedule 24.11.2014