12 янв. 2009 г.

С++: сужение области видимости метода

Область видимости метода в наследнике может быть сужена в C++. После многолетнего java опыта мне кажется это дикостью, да и кроме того - никто не запрещает фактически вызывать такие методы откуда угодно.
класс Foo:
class Foo {
public:
virtual void method() const {
std::cout << "this is Foo::method" << std::endl;
}
};

класс Bar - наследник Foo, сужающий область видимости метода method:
class Bar: public Foo {
private:
virtual void method() const {
std::cout << "this is Bar::method" << std::endl;
}
};


Конечно, на прямую нам никто не даст вызывать Bar::method():
Bar *bar = new Bar;
bar->method();
при компиляции выдаст что-то типа:
$ g++ main.cpp -o main
main.cpp: In function 'int main(int, char**)':
Bar.cpp:2: error: 'virtual void Bar::method() const' is private
main.cpp:4: error: within this context


Однако, ничто не запрещает привести *bar к Foo и таки вызвать method():
Bar *bar = new Bar;
Foo *kindaFoo = dynamic_cast<Foo*>(bar);
kindaFoo->method();

компилируем и смотрим результат:
$ g++ main.cpp -o main && ./main 
this is Bar::method


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

5 комментариев:

unix-junkie комментирует...

Создатели C++ (думаю, виноват не один Страуструп) много экспериментировали.

Их ошибки (и опыт!) были учтены при создании Java.

Равно как и опыт Java был учтён при создании C#.


В рез-те в C++ одно и то же можно сделать не десятком (как в Java), а миллионом разных способов. Не удивляйся =)

Nodir Gulyamov комментирует...

Пожалуй я выскажусь, так как был отправлен на эту страницу Bass-ом и не смог удержаться. :-)
Ну на ум приходит аналогии не целевого использования:

- В лучших традициях ЛОРа - Сам Себе Злой Буратино

- "Можно и отверткой гвозди забивать"

- "Доктор, если я вот так вот делаю, то мне больно"
- "А Вы так не делайте"

Ну а если серьезно, то еще у Скотта Майерса в Совете 33 было сказано, что не нужно переопределять видимость при наследовании. Это практически равносильно разыменованию нулевого указателя. Так конечно можно сделать, но это не правильно.

Раз возникают такие вопросы, очень рекомендую прочитать С. Майерса "Эффективное использование С++". Могу даже поделиться электронными версиями как на русском, так и на английском.

Владимир Долженко комментирует...

2Nodir:
такие мысли использования возникают не из архитектурной необходимости, а из соображений возможностей языка. Прекрасно понимаю, что это есть bad code style и применять такое в реальных проектах не считаю, что есть гуд.
Просто как-то дико это - зачем такие вещи изначально создавались ?

За Майерса буду очень признателен.

Nodir Gulyamov комментирует...

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

Nodir Gulyamov комментирует...

упс, уже увидел на странице адрес, сейчас вышлю.