Перейти к содержимому

Как вызвать protected метод c

  • автор:

Управление доступом к членам (C++)

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

class Point < public: Point( int, int ) // Declare public constructor.; Point();// Declare public default constructor. int &x( int ); // Declare public accessor. int &y( int ); // Declare public accessor. private: // Declare private state variables. int _x; int _y; protected: // Declare protected function for derived classes only. Point ToWindowCoords(); >; 

Доступ по умолчанию находится private в классе и public в структуре или союзе. Спецификаторы доступа класса могут использоваться любое количество раз и в любом порядке. Выделение хранилища для объектов типов классов зависит от реализации. Однако компиляторы должны гарантировать назначение элементов последовательно более высоким адресам памяти между описателями доступа.

Управление доступом к членам

Тип доступа Значение
private Члены класса, объявленные как private могут использоваться только функциями-членами и друзьями (классами или функциями) класса.
protected Члены класса, объявленные как protected могут использоваться функциями-членами и друзьями (классами или функциями) класса. Кроме того, они могут использоваться производными классами данного класса.
public Члены класса, объявленные как public можно использовать любой функцией.

Управление доступом помогает предотвратить использование объектов способами их использования. Эта защита теряется при выполнении явных преобразований типов (приведения).

Управление доступом одинаково применимо ко всем именам: функциям-членам, данным члена, вложенным классам и перечислителям.

Управление доступом в производном классе

Доступность в производном классе членов базового класса и унаследованных членов определяется двумя следующими факторами.

  • Объявляет ли производный класс базовым классом public с помощью описателя доступа.
  • Какой доступ к членам предоставляется в базовом классе.

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

Доступ к членам в базовом классе

private protected public
Всегда недоступно с любым доступом к производным данным private в производном классе, если используется private производное private в производном классе, если используется private производное
protected в производном классе, если используется protected производное protected в производном классе, если используется protected производное
protected в производном классе, если используется public производное public в производном классе, если используется public производное

В следующем примере показано наследование доступа:

// access_specifiers_for_base_classes.cpp class BaseClass < public: int PublicFunc(); // Declare a public member. protected: int ProtectedFunc(); // Declare a protected member. private: int PrivateFunc(); // Declare a private member. >; // Declare two classes derived from BaseClass. class DerivedClass1 : public BaseClass < void foo() < PublicFunc(); ProtectedFunc(); PrivateFunc(); // function is inaccessible >>; class DerivedClass2 : private BaseClass < void foo() < PublicFunc(); ProtectedFunc(); PrivateFunc(); // function is inaccessible >>; int main() < DerivedClass1 derived_class1; DerivedClass2 derived_class2; derived_class1.PublicFunc(); derived_class2.PublicFunc(); // function is inaccessible >

В DerivedClass1 , функция-член PublicFunc является public членом и ProtectedFunc является protected членом, так как BaseClass является базовым классом public . PrivateFunc BaseClass имеет значение private , и недоступно для всех производных классов.

В DerivedClass2 функциях PublicFunc и ProtectedFunc считаются private членами, так как BaseClass это базовый private класс. Опять же, это значит, PrivateFunc что private BaseClass он недоступен для любых производных классов.

Производный класс можно объявить без спецификатора доступа базового класса. В таком случае производный класс считается, private если объявление производного класса использует class ключевое слово. Производные считаются, public если объявление производного класса использует struct ключевое слово. Например, приведенный ниже код

class Derived : Base . 
class Derived : private Base . 
struct Derived : Base . 
struct Derived : public Base . 

Члены, объявленные как private имеющие доступ, недоступны для функций или производных классов, если эти функции или классы не объявлены с помощью friend объявления в базовом классе.

Тип union не может иметь базовый класс.

При указании private базового класса рекомендуется явно использовать private ключевое слово чтобы пользователи производного класса понимали доступ к члену.

Управление доступом и статические члены

При указании базового класса как private он влияет только на нестатические члены. Открытые статические члены по-прежнему доступны в производных классах. Однако доступ к членам базового класса с помощью указателей, ссылок или объектов может потребовать преобразования, который снова применяет управление доступом. Рассмотрим следующий пример:

// access_control.cpp class Base < public: int Print(); // Nonstatic member. static int CountOf(); // Static member. >; // Derived1 declares Base as a private base class. class Derived1 : private Base < >; // Derived2 declares Derived1 as a public base class. class Derived2 : public Derived1 < int ShowCount(); // Nonstatic member. >; // Define ShowCount function for Derived2. int Derived2::ShowCount() < // Call static member function CountOf explicitly. int cCount = ::Base::CountOf(); // OK. // Call static member function CountOf using pointer. cCount = this->CountOf(); // C2247: 'Base::CountOf' // not accessible because // 'Derived1' uses 'private' // to inherit from 'Base' return cCount; > 

В предыдущем примере кода управление доступом запрещает преобразование указателя на Derived2 к указателю на Base . Указатель this неявно имеет тип Derived2 * . Чтобы выбрать функцию CountOf , this необходимо преобразовать в тип Base * . Такое преобразование не допускается, так как Base является косвенным базовым классом Derived2 private. Преобразование в private тип базового класса допустимо только для указателей на непосредственные производные классы. Поэтому указатели типа Derived1 * можно преобразовать в тип Base * .

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

Члены и друзья производного класса T , могут преобразовать указатель в указатель T на прямой базовый private класс T .

Доступ к виртуальным функциям

Управление доступом, применяемое к virtual функциям, определяется типом, используемым для вызова функции. Переопределение объявлений функции не влияет на управление доступом для данного типа. Например:

// access_to_virtual_functions.cpp class VFuncBase < public: virtual int GetState() < return _state; >protected: int _state; >; class VFuncDerived : public VFuncBase < private: int GetState() < return _state; >>; int main() < VFuncDerived vfd; // Object of derived type. VFuncBase *pvfb = &vfd; // Pointer to base type. VFuncDerived *pvfd = &vfd; // Pointer to derived type. int State; State = pvfb->GetState(); // GetState is public. State = pvfd->GetState(); // C2248 error expected; GetState is private; > 

В предыдущем примере вызов виртуальной функции GetState с помощью указателя на вызовы VFuncDerived::GetState типов VFuncBase и GetState рассматривается как public . Однако вызов GetState с помощью указателя типа VFuncDerived является нарушением управления доступом, так как GetState объявляется private в классе VFuncDerived .

Виртуальную функцию GetState можно вызвать с помощью указателя на базовый класс VFuncBase . Это не означает, что вызываемая функция является базовой версией этой функции.

Управление доступом с множественным наследованием

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

На схеме показана следующая иерархия наследования: класс VBase является базовым классом. Класс LeftPath наследует от VBase с помощью виртуальной виртуальной private базы данных. Класс RightPath также наследует от VBase, но с помощью виртуальной виртуальной public базы данных. Наконец, класс Производный наследует от класса LeftPath и класса RightPath с помощью public LeftPath, public RightPath.

Доступ вдоль линий графа наследования

На этом рисунке обращение к имени, которое было объявлено в классе VBase , всегда будет выполняться через класс RightPath . Правильный путь является более доступным, так как RightPath объявляется VBase как базовый public класс, а LeftPath объявляется VBase как private .

Как использовать protected метод в чужого класса?

Добрый день! Не могу разобраться, как в своём наследующем классе использовать protected метод чужого базового класса.
Например, есть у меня класс MyClass , я наследую класс YourClass с методом
protected void meth1() Я ничего не могу менять в чужом классе, геттеры и сеттеры не помогут, тогда как мне использовать этот метод, какие способы возможны? Спасибо.

Отслеживать
60 10 10 бронзовых знаков
задан 7 авг 2013 в 12:07
21 4 4 бронзовых знака
Опишит подробно кто кого наследует. И из какого места требуется получить доступ к protected методу
7 авг 2013 в 12:36
7 авг 2013 в 14:57

Приведите код. Непонятно, где проблема: protected-методы из объектов порождённых классов всегда можно было использовать без проблем.

7 авг 2013 в 18:28

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

В данном случае есть самый простой вариант — создать в своем классе public метод, который и будет осуществлять вызов protected метод у предка.

Отслеживать
ответ дан 7 авг 2013 в 12:21
Dmitry Lepeshkin Dmitry Lepeshkin
756 4 4 серебряных знака 8 8 бронзовых знаков

Вы можете без проблем использовать методы, помеченные модификатором доступа protected , в классах-наследниках. Для этого и был введен данный модификатор доступа, этим он и отличается от private

Ключевое слово protected является модификатором доступа к члену. Доступ к члену с модификатором protected возможен внутри класса и из производных экземпляров класса.

public class YourClass < protected int YourMethod() < return 1; >> public class MyClass : YourClass < public MyClass () < var a = YourMethod(); // вернет 1 >> 

Подробнее почитать про protected тут

Как вызвать protected метод c

Не компилится в VC2003, VC2005, ошибка

error C2248: ‘Parent::prot’ : cannot access protected member declared in class ‘Parent’

Я до сих пор считал, что это работать должно. Это действительно не должно работать по стандарту? Есть какие-то аргументы — из каких соображений? Соображения — не столько ссылки на стандарт, столько обоснования — почему было принято такое, на мой взгляд, странное решение.

Делай что должно, и будь что будет
Re: Доступ к protected членам родителя

От: Andrew S http://alchemy-lab.com
Дата: 02.02.07 11:02
Оценка: 19 (2)

SH>class Child : public Parent
SH> <
SH>public:

SH> void m1()
SH> void m2(Child* c) prot();>
SH> void m3(Parent* p) prot();> // Тут ошибка
SH>>;

SH>int main()
SH> <
SH>>
SH>[/ccode]
SH>Я до сих пор считал, что это работать должно. Это действительно не должно работать по стандарту? Есть какие-то аргументы — из каких соображений? Соображения — не столько ссылки на стандарт, столько обоснования — почему было принято такое, на мой взгляд, странное решение.

Разрешение доступа выбирается на основе статического типа. Динамический тип компилятору может быть неизвестен — это же очевидно. Например, пусть prot будет виртуальной функцией, перекрытой потом каким-либо потомком. Почему это, собственно, вы должны мочь ее вызвать из совершенно другого потомка, когда тот, кто ее перекрывает, явно рассчитывает только на себя?
Это во-первых. А во-вторых — |\/\/\/\/\/\|. http://gzip.rsdn.ru/Forum?mid=2297667

Автор: Pavel Chikulaev
Дата: 11.01.07
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[2]: Доступ к protected членам родителя

От: SergH
Дата: 02.02.07 11:18
Оценка:

Здравствуйте, Andrew S, Вы писали:

AS>Разрешение доступа выбирается на основе статического типа. Динамический тип компилятору может быть неизвестен — это же очевидно. Например, пусть prot будет виртуальной функцией, перекрытой потом каким-либо потомком. Почему это, собственно, вы должны мочь ее вызвать из совершенно другого потомка, когда тот, кто ее перекрывает, явно рассчитывает только на себя?

Расчитывал бы на себя — сделал бы приватной. Я просто считал, что protected функция базового класса доступна любому потомку, причём не только для объектов своего класса, но и для любых наследников базового класса.

Мне и надо таким способом вызвать функцию другого класса. Иначе я бы, в конце концов, приведение типа сделал. Описываю ситуацию.

class base < public: virtual int func(const base* b) const = 0; protected: virtual int func2() const = 0; >;

Клиенты имеют доступ только к первой, потомки — к первой и второй. В результате, в реализации потомком func можно использовать b->func2(). А из-за ограничений получается, что либо нельзя, либо приходится делать func2 доступной всем. А всем она нафиг не нужна..

AS>Это во-первых. А во-вторых — |\/\/\/\/\/\|. http://gzip.rsdn.ru/Forum?mid=2297667

Автор: Pavel Chikulaev
Дата: 11.01.07

Спасибо. Значит, не я один такой.

Делай что должно, и будь что будет
Re: Доступ к protected членам родителя

От: valker
Дата: 02.02.07 11:24
Оценка:

Здравствуйте, SergH, Вы писали:

SH>Я до сих пор считал, что это работать должно. Это действительно не должно работать по стандарту? Есть какие-то аргументы — из каких соображений? Соображения — не столько ссылки на стандарт, столько обоснования — почему было принято такое, на мой взгляд, странное решение.

Грубо говоря, protected интерфейс класса делается, чтобы производные классы могли вызывать эти функции (например, как реализации по умолчанию).
Это имеет смысл, если делать базовый класс так:

class Base < public: void something(Base* base) < void doSomething(base); > private: virtual void doSomething(Base*) = 0; protected: void someDefaultDoSomethingOrItsPart(/*. */) < //. > >;

В таком случае, вызывать someDefaultDoSomethingOrItsPart() смогут только наследники. По логике архитектуры они должны это делать в реализации doSomething(), которая может вызываться только из something(). Поэтому вызывая someDefaultDoSomethingOrItsPart() в производном классе по указателю на базовый, ты не можешь гарантировать инвариант (вызов someDefaultDoSomethingOrItsPart() внутри обработчика something()).
Надеюсь, понятно объяснил.
imho.
Спасибо.

Re[2]: Доступ к protected членам родителя

От: SergH
Дата: 02.02.07 11:32
Оценка:

Здравствуйте, valker, Вы писали:

V>Спасибо.

Тебе спасибо Немного выше я описал свою ситуацию.. Кроме того, раз уж про инварианты — никто не мешает производному классу их и так нарушать сколько угодно. Например, вызывать эту защищённую функцию два раза. Или не из той публичной, которая подразумевалась.. Куча вариантов.

Делай что должно, и будь что будет
Re[3]: Доступ к protected членам родителя

От: Andrew S http://alchemy-lab.com
Дата: 02.02.07 12:49
Оценка: 6 (1)

AS>>Разрешение доступа выбирается на основе статического типа. Динамический тип компилятору может быть неизвестен — это же очевидно. Например, пусть prot будет виртуальной функцией, перекрытой потом каким-либо потомком. Почему это, собственно, вы должны мочь ее вызвать из совершенно другого потомка, когда тот, кто ее перекрывает, явно рассчитывает только на себя?

SH>Расчитывал бы на себя — сделал бы приватной.

Не тот, кто объявляет, а тот кто перекрывает\использует. Модификатор доступности обозначает разрешение использовать члены класса статическим типам (потому что динамический на этапе компиляции неизвестен). Т.е. каким образом код может обращаться к именам членов класса, и не более того.
Ровно так же (на основании статического типа) выбираются параметры по умолчанию у перегружаемых\перекрываемых функций, по тем же самым причинам.
Почему так.. ну, например, смотри:

class base < protected: void f1()<> >; class child1:public base < public: using base::f1; >; class child2:public child1 < private: using child1::f1; >; void f1(base *b) < b->f1(); > void f2(child1 *c) < c->f1(); > child2 c; f1(&c); // f2(&c); // 

SH>Я просто считал, что protected функция базового класса доступна любому потомку, причём не только для объектов своего класса, но и для любых наследников базового класса.

Она и доступна. Именно потомку, а не базе. Решение о доступе принимается исходя из _статического_ типа. Статический тип у вас — база.

SH>Мне и надо таким способом вызвать функцию другого класса. Иначе я бы, в конце концов, приведение типа сделал. Описываю ситуацию.

SH>Клиенты имеют доступ только к первой, потомки — к первой и второй. В результате, в реализации потомком func можно использовать b->func2(). А из-за ограничений получается, что либо нельзя, либо приходится делать func2 доступной всем. А всем она нафиг не нужна..

Значит, нужна, если потомки хотят ее вызывать у _базы_. Если очень надо вызвать — есть простое не очень ill formed решение:

. int f1(base *b) < struct LocalChild:public base < public:using base::f1; >; static_cast(b)->f1(); >

А вообще — защищенные виртуальные методы — нонсенс и баг проектирования. Виртуальный метод должен быть либо открытый и определять интерфейс, либо быть закрытым, и тогда уже использоваться в паттерне NVI.

http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re: Доступ к protected членам родителя

От: Bell
Дата: 02.02.07 13:15
Оценка: 18 (1)

Здравствуйте, SergH, Вы писали:

Теория уже была, так что попробую предложить костыль, который может быть поможет тебе обойти проблему:

class base < public: virtual int func(const base* b) const = 0; protected: virtual int func2() const = 0;//можно и приватной сделать для вящей правильности static int func2_s(const base* pb) < return pb->func2(); > >; class d : public base < public: void m1() void m2(d* pd) func2();> void m3(base* pb) base::func2_s(pb);> >;

Любите книгу — источник знаний (с) М.Горький
Re[4]: Доступ к protected членам родителя

От: SergH
Дата: 02.02.07 13:19
Оценка:

Здравствуйте, Andrew S, Вы писали:

AS>Не тот, кто объявляет, а тот кто перекрывает\использует.

Воот. Я считаю, что если базовый класс сказал protected, значит потомки не должны расчитывать на что-то другое. Ну ладно, не будем спорить о философии..

AS>Модификатор доступности обозначает разрешение использовать члены класса статическим типам (потому что динамический на этапе компиляции неизвестен). Т.е. каким образом код может обращаться к именам членов класса, и не более того.
AS>Ровно так же (на основании статического типа) выбираются параметры по умолчанию у перегружаемых\перекрываемых функций, по тем же самым причинам.
AS>Почему так.. ну, например, смотри:

Не, не так. Решение я хочу принимать решение о доступе на основе статического типа. Это естественно. В богопротивных интерпретируемых языках можно делать это динамически, но мы пока остаёмся в рамках C++. Но просто я хочу расширить круг тех, кому «можно».

Я хочу, чтобы для потомка публичный интерфейс базы состоял из публичных и из защищённых методов базы. Причём не только при использовании «своего» экземпляра базы, или объекта такого же типа, но и при использовании любого потомка той же базы.

AS>А вообще — защищенные виртуальные методы — нонсенс и баг проектирования. Виртуальный метод должен быть либо открытый и определять интерфейс,

Это попытка ввести два интерфейса — для всех и для своих. Один — пользовательский, с ограниченным доступом и одной единственной функцией, второй — с несколькими служебными функциями.

AS> либо быть закрытым, и тогда уже использоваться в паттерне NVI.

Почитал, прикольная штука. Я подумаю и в эту сторонцу тоже.

Делай что должно, и будь что будет
Re[2]: Доступ к protected членам родителя

От: SergH
Дата: 02.02.07 13:34
Оценка:

Здравствуйте, Bell, Вы писали:

B>Теория уже была, так что попробую предложить костыль, который может быть поможет тебе обойти проблему:

Ну, это, конечно, извращение, но я обязательно так и сделаю Спасибо большое.

Делай что должно, и будь что будет
Re[5]: Доступ к protected членам родителя

От: Andrew S http://alchemy-lab.com
Дата: 02.02.07 14:53
Оценка:

AS>>Не тот, кто объявляет, а тот кто перекрывает\использует.

SH>Воот. Я считаю, что если базовый класс сказал protected, значит потомки не должны расчитывать на что-то другое. Ну ладно, не будем спорить о философии..

Не так. Базовый класс сказал, что доступ к членам данного статического типа возможен только из статического типа потомков. Все.

AS>>Модификатор доступности обозначает разрешение использовать члены класса статическим типам (потому что динамический на этапе компиляции неизвестен). Т.е. каким образом код может обращаться к именам членов класса, и не более того.
AS>>Ровно так же (на основании статического типа) выбираются параметры по умолчанию у перегружаемых\перекрываемых функций, по тем же самым причинам.
AS>>Почему так.. ну, например, смотри:

SH>[. ]

SH>Не, не так. Решение я хочу принимать решение о доступе на основе статического типа. Это естественно. В богопротивных интерпретируемых языках можно делать это динамически, но мы пока остаёмся в рамках C++. Но просто я хочу расширить круг тех, кому «можно».

Я привел примеры, когда на основе статического типа данное решения однозначно принять нельзя.

SH>Я хочу, чтобы для потомка публичный интерфейс базы состоял из публичных и из защищённых методов базы. Причём не только при использовании «своего» экземпляра базы, или объекта такого же типа, но и при использовании любого потомка той же базы.

Дык это.. я вот хочу, чтобы оно само вообще работало, и не надо было кодить. пока не получается Еще раз — я привел примеры, почему так нельзя.

AS>>А вообще — защищенные виртуальные методы — нонсенс и баг проектирования. Виртуальный метод должен быть либо открытый и определять интерфейс,

SH>Это попытка ввести два интерфейса — для всех и для своих. Один — пользовательский, с ограниченным доступом и одной единственной функцией, второй — с несколькими служебными функциями.

Вы разделяйте динамический и статический тип пользователя. При вызове из метода класса статический тип — правильный, при вызове по указателю — статический тип — это база. И если делать по-другому, возникает множество проблем.

А делать так, как хотите вы, проще через NVI — в этом случае, не вы будете вызывать методы базы, а база — ваши перекрытые виртуальные методы.

http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re: Доступ к protected членам родителя

От: Vain google.ru
Дата: 02.02.07 15:28
Оценка:

Здравствуйте, SergH, Вы писали:

SH>Вот такой код:
SH>

SH>class Parent SH>< SH>public: SH> void publ() <> SH>protected: SH> void prot() <> SH>>; SH>class Child : public Parent SH>< SH>public: SH> void m1() SH> void m2(Child* c) prot();> SH> void m3(Parent* p) prot();> // Тут ошибка SH>>; SH>int main() SH>< SH>> SH>

SH>Не компилится в VC2003, VC2005, ошибка
SH>

error C2248: ‘Parent::prot’ : cannot access protected member declared in class ‘Parent’

SH>Я до сих пор считал, что это работать должно. Это действительно не должно работать по стандарту? Есть какие-то аргументы — из каких соображений? Соображения — не столько ссылки на стандарт, столько обоснования — почему было принято такое, на мой взгляд, странное решение.
Можно кастыль вынести токо в debug:

#include #ifdef _DEBUG #define _DEBUG_VIRTUAL virtual #else #define _DEBUG_VIRTUAL #endif #define ASSERT_DCAST_POINTER(to,from) \ AssertDCastPointer(from) templateclass TO,class FROM> TO AssertDCastPointer(FROM* ptr) < #ifdef _DEBUG TO toptr = dynamic_cast(ptr); assert(toptr); return toptr; #else return static_cast(ptr); #endif > class Parent < public: void publ() <> protected: _DEBUG_VIRTUAL ~Parent() <> //Polymorphic in debug only void prot() <> >; class Child1 : public Parent < static Child1* AutoCast(Parent* p) < return ASSERT_DCAST_POINTER(Child1*,p); > public: void m1() void m2(Child1* c) prot();> void m3(Parent* p) prot();> >; class Child2 : public Parent < static Child2* AutoCast(Parent* p) < return ASSERT_DCAST_POINTER(Child2*,p); > public: void m1() void m2(Child2* c) prot();> void m3(Parent* p) prot();> >; int main() < Child1 c1; Child2 c2; Child1* pc1 = &c1; Child2* pc2 = &c2; pc1->m3(pc1); pc2->m3(pc2); pc1->m3(pc2); //Here error, beware the debug, fear in release! :) return 0; >

но для этого в дебуге надо включить поддержку RTTI (/GR)

[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]

Re[6]: Доступ к protected членам родителя

От: SergH
Дата: 02.02.07 15:55
Оценка:

Здравствуйте, Andrew S, Вы писали:

AS>Я привел примеры, когда на основе статического типа данное решения однозначно принять нельзя.

Ок, раз ты настаиваешь, объясняю на твоих примерах

class base < protected: void f1()<> >; class child1 : public base < public: using base::f1; >; class child2 : public child1 < private: using child1::f1; >; void f1(base *b) < b->f1(); // нельзя. Делаем вывод на основе того, что f1 не друг base > void f2(child1 *c) < c->f1(); // можно. Делаем вывод на основе того, что f1 - открытый метод класс child1 > // А это всё не важно - абсолюно нет разницы, какие у этих объектов настоящие типы

В чём проблема. Вроде же C++ так и работает.

AS>Дык это.. я вот хочу, чтобы оно само вообще работало, и не надо было кодить. пока не получается Еще раз — я привел примеры, почему так нельзя.

Извини, но если бы я не читал твои сообщения последние пару лет, я бы усомнился в твоей профессиональности

SH>>Это попытка ввести два интерфейса — для всех и для своих. Один — пользовательский, с ограниченным доступом и одной единственной функцией, второй — с несколькими служебными функциями.

AS>Вы разделяйте динамический и статический тип пользователя. При вызове из метода класса статический тип — правильный, при вызове по указателю — статический тип — это база. И если делать по-другому, возникает множество проблем.

Нет, я не хочу разделять статический и динамический тип пользователя. Всё на этапе компиляции, всё элементарно решается изменением трактовки понятия protected.

class base < protected: void f1()<> >; class child1 : public base < public: void doSome(base* b) < b->f1(); // Можно. Делаем вывод на основании того, что child1 - потомок base, а f1 - protected, а не private > >; class child2: public base < public: void doAny(base* b) < b->f1(); // Можно. Делаем вывод на основании того, что child2 - потомок base, а f1 - protected, а не private > >; child2 c2; child1 c1; c1.doSome(c2); // Да сколько угодно. Всё можно c2.doSome(c1);

Где здесь нужен динамический тип? Не вижу, если видишь — ткни пальцем, я спасибо скажу.

AS>А делать так, как хотите вы, проще через NVI — в этом случае, не вы будете вызывать методы базы, а база — ваши перекрытые виртуальные методы.

Урок №157. Наследование и cпецификатор доступа protected

На предыдущих уроках мы говорили о том, как работает наследование в языке C++. Во всех наших примерах мы использовали открытое наследование.

На этом уроке мы рассмотрим детально этот тип наследования, а также два других типа: private и protected. Также поговорим о том, как эти типы наследований взаимодействуют со спецификаторами доступа для разрешения или ограничения доступа к членам.

Оглавление:

  1. Спецификатор доступа protected
  2. Когда следует использовать спецификатор доступа protected?
  3. Типы наследований. Доступ к членам
    • Наследование типа public
    • Наследование типа private
    • Наследование типа protected
  4. Финальный пример
  5. Заключение

Спецификатор доступа protected

Мы уже рассматривали спецификаторы доступа private и public, которые определяют, кто может иметь доступ к членам класса. В качестве напоминания: доступ к public-членам открыт для всех, к private-членам доступ имеют только члены того же класса, в котором находится private-член. Это означает, что дочерние классы не могут напрямую обращаться к private-членам родительского класса!

class Parent

int m_private ; // доступ к этому члену есть только у других членов класса Parent и у дружественных классов/функций (но не у дочерних классов)

int m_public ; // доступ к этому члену открыт для всех объектов

Примечание: public = «открытый», private = «закрытый», protected = «защищенный».

В языке C++ есть третий спецификатор доступа, о котором мы еще не говорили, так как он полезен только в контексте наследования. Спецификатор доступа protected открывает доступ к членам класса дружественным и дочерним классам. Доступ к protected-члену вне тела класса закрыт.

class Parent
int m_public ; // доступ к этому члену открыт для всех объектов

int m_private ; // доступ к этому члену открыт только для других членов класса Parent и для дружественных классов/функций (но не для дочерних классов)

int m_protected ; // доступ к этому члену открыт для других членов класса Parent, дружественных классов/функций, дочерних классов

class Child : public Parent
m_public = 1 ; // разрешено: доступ к открытым членам родительского класса из дочернего класса
m_private = 2 ; // запрещено: доступ к закрытым членам родительского класса из дочернего класса
m_protected = 3 ; // разрешено: доступ к защищенным членам родительского класса из дочернего класса
Parent parent ;
parent . m_public = 1 ; // разрешено: доступ к открытым членам класса извне
parent . m_private = 2 ; // запрещено: доступ к закрытым членам класса извне
parent . m_protected = 3 ; // запрещено: доступ к защищенным членам класса извне

В примере, приведенном выше, вы можете видеть, что член m_protected класса Parent напрямую доступен дочернему классу Child, но доступ к нему для членов извне — закрыт.

Когда следует использовать спецификатор доступа protected?

К protected-членам родительского класса доступ открыт для членов дочернего класса, а это означает, что если вы позже измените что-либо в protected-члене (тип данных, значение и т.д.), то вам придется внести изменения как в родительский, так и во все дочерние классы. Поэтому использование спецификатора доступа protected наиболее полезно, когда вы будете наследовать только свои же классы и количество дочерних классов будет небольшое. Таким образом, если вы внесете изменения в реализацию родительского класса, и вам понадобится обновить все дочерние классы, то вы сможете сделать эти обновления сами и это не займет много времени (так как дочерних классов будет немного).

Создание private-членов предоставляет лучшую инкапсуляцию и изолирует родительские классы от изменений, вызванных дочерними классами. Но цена этому — дополнительное создание открытого или защищенного интерфейса (способа взаимодействия других объектов с классами и их членами, т.е. геттеры и сеттеры). Это дополнительная работа, которая не стоит того, если вы сами работаете со своими же классами (чужие классы не обращаются к вашему классу) и количество дочерних классов небольшое.

Типы наследований. Доступ к членам

Существует три типа наследований классов:

public;

private;

protected.

Для определения типа наследования нужно просто указать нужное ключевое слово возле наследуемого класса:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *