dil: (Default)
dil ([personal profile] dil) wrote2005-03-31 04:49 pm

Посыпаю голову пеплом, ухожу в монастырь



Берём простейший код:
class B {
  public:
    void method(char c);
    void method(int i);
};

class M {
 int i;
};

class D: public B {
  public:
    void method(M);
};

int main() {
  D d;
  M m;

  d.method('c'); // не работает
  d.method(0); // тоже не работает
  d.method(m); // работает
}

И обнаруживаем, что для объекта производного класса методы базового нифига не вызываются (error: no matching function for call to `D::method(char)'), потому что они перекрыты одноимённым методом в производном.
И где, спрашивается, это ваше хвалёное наследование?
Да, если из D убрать одноимённый метод, то всё работает.
Кто знает, чем обусловлена такая странность?

[identity profile] dma.livejournal.com 2005-03-31 12:57 pm (UTC)(link)
Хе. Забавный overloading.
А он должен так работать, вообще?

(удаляется, подумывая, не научиться ли писать на C++)

[identity profile] dil.livejournal.com 2005-03-31 12:59 pm (UTC)(link)
Я думал, что должен. И таки работает, если в производном классе нет ни одной одноимённой функции.
А вот если есть хоть одна, даже не перекрывающая по аргументам базовый вариант, то фиг.

[identity profile] sergtch.livejournal.com 2005-03-31 01:19 pm (UTC)(link)
Попробуй так вота:

class D: public B {
public:
using B::method;

void method(M);
};

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

[identity profile] dil.livejournal.com 2005-03-31 01:39 pm (UTC)(link)
Так работает. Но как-то оно.. неаккуратненько получается, доктор.

[identity profile] execve.livejournal.com 2005-03-31 01:29 pm (UTC)(link)
Это т.н. hiding.

Исправь class D так:
class D: public B {
  using B::method;
  public:
    void method(M);
};

[identity profile] dil.livejournal.com 2005-03-31 01:41 pm (UTC)(link)
Почему так получается, мне уже объяснили. А зачем - не объяснили :(

[identity profile] 1master.livejournal.com 2005-03-31 01:32 pm (UTC)(link)
В VC++.net нихт арбайтен. А ты в gcc небось пробовал? Вообще любопытно, надо будет дома в трупик страуса глянуть.

[identity profile] dil.livejournal.com 2005-03-31 01:40 pm (UTC)(link)
g++ 3.3.5.
Во времена Страуса namespace'ы ещё не изобрели.

[identity profile] 1master.livejournal.com 2005-03-31 01:43 pm (UTC)(link)
Ты отстал от страуса. В последнем издании полный комплект удовольствий ;)

[identity profile] dil.livejournal.com 2005-03-31 01:45 pm (UTC)(link)
Может быть. Я c++ изучал году эдак в 92, а последний раз применял на практике в 97-м..

[identity profile] 1master.livejournal.com 2005-03-31 01:51 pm (UTC)(link)
А я вот наоборот, о тонкой версии страуса знаю только по рассказам ;)

[identity profile] shadowtramp.livejournal.com 2005-03-31 02:19 pm (UTC)(link)
Я чую, из курилки в вашу комнату дым от неслабой травы заносит.
То, что ты нарисовал, называется hiding, оно же - сокрытие, и вступает в силу, если есть коллизия имён у потомков и предков. Для наследования необходимо, чтобы а) у фнукций были идентичные сигнатуры и наличие где-нибудь (где тебе больше нравится, но я обычно пишу в начале строки, где объявляю функцию) ключевого слова virtual, или б) отсутствие символов с таким же именем в классе наследнике.
Если же ты хочешь из класса предка вытащить символы и сделать их доступными в классе потомке, то надо действительно использовать ключевое слово using.
Теперь про то, чем обусловленно: представь, что все символы из класса предка экспортируются в класс наследник. Ты не можешь отказаться от этого поведения. Если ты хочешь ввести в потомке символ, разрешаемый по более общему типу, то не можешь этого сделать. Ты не сможешь отловить на этапе компиляции целую кучу ошибок. В существующем порядке ты можешь сам написать, какие символы импортировать.

[identity profile] dil.livejournal.com 2005-03-31 02:43 pm (UTC)(link)
1) Коллизии не наблюдаю. Mangled имена методов абсолютно разные получаются.

а) virtual тут вовсе ни при чём, я про полиморфизм ничего не гворил, по ссылке ничего не вызывал, я хочу просто для объекта вызывать метод из его класса, если он есть, а если нет - то унаследованный от базового.

2) не понимаю, чем принципиально отличается перегрузка невиртуальных методов в пределах одного класса и в базовом и порождённом. Пойдем на кухню, ты мне на пальцах покажешь


[identity profile] anatolix.livejournal.com 2005-03-31 03:24 pm (UTC)(link)
Overloading вообще для безопасности не работает across different scopes.
Т.е. вот такой пример есть в страуструпе:

void f(int);
void g()
{
void f(double);
f(1) ; // call f(double)
}

И в принципе идея здравая нужно сказать.

[identity profile] shadowtramp.livejournal.com 2005-04-01 08:32 pm (UTC)(link)
> Пойдем на кухню, ты мне на пальцах покажешь
11 апреля, ок?

[identity profile] bacek.livejournal.com 2005-03-31 02:30 pm (UTC)(link)
-W -Wall спасёт отца русской демократии.

[identity profile] bormotov.livejournal.com 2005-03-31 06:07 pm (UTC)(link)
rm -f `which g++` (и всё такое прочее)
спасет еще лучше :))))

Вот то-ли дело "нога прострелить себе вы" :))

[identity profile] dil.livejournal.com 2005-03-31 06:50 pm (UTC)(link)
Да я его только сегодня и поставил, чтоб проверить :)

[identity profile] bormotov.livejournal.com 2005-04-01 05:38 am (UTC)(link)
проверил?
Можно удалять! :))