• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Zepsuty protected?

Object Storage Arubacloud
0 głosów
161 wizyt
pytanie zadane 23 stycznia 2016 w C i C++ przez Dash Nałogowiec (29,650 p.)

Trafiłem na dość dziwny problem, nie rozumiem istoty działania mojego kodu: 

class Base
{
public:
  typedef std::unique_ptr<Base> Ptr;

protected:
   virtual void method() const {//...};

   std::vector<Ptr> children;
};

class Derived : public base
{

 virtual void method() const 
{
 for (const Ptr& child: children )
	{
	  child->method();
	}

};

} 

Klauzula protected pozwala mi na dostęp do wektora children ale nie pozwala mi wywołać na jego elementach metody method(), pomimo że wywołuję ją w klasie dziedziczącej. Przy zmiani etykiety na public w Base, wszystko działa. O co tutaj chodzi? 

1 odpowiedź

+1 głos
odpowiedź 23 stycznia 2016 przez Radfler VIP (101,030 p.)
wybrane 23 stycznia 2016 przez Dash
 
Najlepsza

Pierwszy raz spotykam się z takim problemem, ale spróbuję Ci go naświetlić. Nawiązując do cppreference.com:

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)

Wywołując funkcję składową method na rzecz obiektu, który siedzi w wektorze children łamiesz w pewnym sensie punkt 2, gdyż wektor zawiera w sobie wskaźniki na obiekty typu (statycznego) Base. A na logikę rzecz biorąc: Base dziedziczy z Base? Nie, bzdura! Oznacza to, że praca na tym obiekcie nie jest możliwa, gdyż jest on niedostępny dla klas dziedziczących. Tu masz jeszcze mój test:

#include <type_traits>
struct Derived1; // fwd
struct Derived2; // fwd

struct Base {

protected:

	// Wskaźnik na obiekt klasy bazowej (Base)
	Base* foo;

	// Wskaźniki na obiekty klas dziedziczących (Derived1, Derived2)
	Derived1* foo1;
	Derived2* foo2;

	// Jakaś wartosć
	int value;

	virtual void foobar() { }

};

struct Derived1 : public Base {

	void foobar() override;

};

struct Derived2 : public Base {

	void foobar() override;

};

void Derived1::foobar() {

	// Praca nie jest możliwa, decltype(*foo) nie dziedziczy z Base, tylko nią jest.
	foo->foobar();
	
	// Typy decltype(*foo1) i decltype(*foo2) dziedziczą z Base, więc praca jest możliwa
	foo1->foobar();
	foo2->foobar();

	using FooType = std::decay_t<decltype(*foo)>;
	using Foo1Type = std::decay_t<decltype(*foo1)>;
	using Foo2Type = std::decay_t<decltype(*foo2)>;

	static_assert(std::is_same<FooType, Base>::value &&
				  std::is_same<Foo1Type, Derived1>::value &&
				  std::is_same<Foo2Type, Derived2>::value, "error");

	// Błąd wystąpił z powodu !std::is_same<Base, FooType>::value
	static_assert(std::is_base_of<Base, FooType>::value && !std::is_same<Base, FooType>::value &&
				  std::is_base_of<Base, Foo1Type>::value && !std::is_same<Base, Foo1Type>::value &&
				  std::is_base_of<Base, Foo2Type>::value && !std::is_same<Base, Foo2Type>::value, "error");

	// Niejawne użycie this, a decltype(*this) dziedziczy z Base
	value = 0;

}

void Derived2::foobar() {

	// Patrz wyżej
	foo->foobar();
	foo1->foobar();
	foo2->foobar();

	value = 0;

}

Rozwiązaniem może być umieszczenie deklaracji friend w klasie Base.

komentarz 23 stycznia 2016 przez Dash Nałogowiec (29,650 p.)

Dekleracja friend rozwiązuje problem, tak samo jak zmiana protected->public. Bardziej ciekawił mnie sam mechanizm, i znalazłem coś takiego, może Ciebie też zainteresuje :) : 

Even though access control in C++ works on per-class basis (as opposed to per-instance basis), protected access specifier has some peculiarities.

The language specification wants to ensure that you are accessing a protected member of some base subobject that belongs to the derived class. You are not supposed to be able access protected members of some unrelated independent objects of base type. In particular, you cannot access protected members of freestanding objects of base type. You are only allowed to access protected members of base objects that are embedded into derived objects as base subobjects.

For this reason, you have to access protected members through pointer->member syntax, reference.member or object.member syntax, where the pointer/reference/object refers to the derivedclass.

W sumie dość przydatne na przyszłość. 

Co do tego że Base nie dziedziczy z Base, to ja patrzyłem z punktu że protected to w zasadzie rozszerzony private, dostępny z klas pochodnych oraz "własnej". Wtedy działamy na zasadzie metody private od strony klasy pochodnej. Jednak było to błędne rozumowanie. 

komentarz 23 stycznia 2016 przez Radfler VIP (101,030 p.)
Całkiem przydatne, ale to nie zmienia faktu, że nie mam głowy do takich rzeczy :v

Podobne pytania

0 głosów
0 odpowiedzi 289 wizyt
pytanie zadane 22 września 2019 w C i C++ przez niezalogowany
0 głosów
0 odpowiedzi 134 wizyt
pytanie zadane 20 maja 2017 w JavaScript przez Sławek Obywatel (1,270 p.)
0 głosów
1 odpowiedź 173 wizyt

92,628 zapytań

141,491 odpowiedzi

319,862 komentarzy

62,011 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...