LINUX.ORG.RU

перегрузка виртуальных функций.

 


0

2

есть вот такой код:

#include<iostream>

class BaseClass
{
public:
	virtual void f(int a, int b);
	virtual void f(float e, float f, int a, int b) =0;
};


void BaseClass::f(int a, int b) {
	return this->f( 0, 0, a, b);
}


class MyClass : public BaseClass
{
public:
	virtual void f(float e, float f, int a, int b) override {
		std::cout << "MyStorage" << std::endl;
	}
};
int main(int argc, char* argv[]) {
	MyClass *ms = new MyClass();
	ms->f(0, 10);
	return 0;
}

и ошибка компиляции

  In function 'int main(int, char**)': 
27:13: error: no matching function for call to 'MyClass::f(int, int)' 
27:13: note: candidate is:
21:15: note: virtual void MyClass::f(float, float, int, int) 21:15: note: candidate expects 4 arguments, 2 provided

а если вызывать так:

	BaseClass *ms = new MyClass();
	ms->f(0, 10);

то все работает. а почему?


Производный класс скрывает имена функций базового класса.
Мэйерс С. - Эффективное использование C++ (3-е издание). Правило 33.

mkam ()

У MyClass нет функции f(int,int), что непонятно-то?

MyClass *ms = new MyClass();
ms->BaseClass::f(0, 10);

fluorite ★★★★★ ()
Ответ на: комментарий от fluorite

нет, но он то его наследник

class MyClass : public BaseClass
lsv ()
Ответ на: комментарий от mkam

а подробнее можно? MyClass является потомком класса, а как он скрывает имена?

lsv ()
Ответ на: комментарий от lsv

Предлагаю скачать книжку, на которую я сослался — https://yadi.sk/i/QTBFsE_WjfoCY
Именно в той главе Скотт «Наше всё» Мэйерс ответит на твой вопрос и расскажет как это пофиксить.

mkam ()
Ответ на: комментарий от fluorite
ms->BaseClass::f(0, 10);

Если потом переопределить в дочернем классе и вторую функцию, то эта строчка не сломается, а делать будет странную вещь, которая вряд ли кому-либо нужна. Лучше всё-таки

static_cast<BaseClass *>(ms)->f(0, 10);
если сабжевые классы менять не хочется или не можется. Иначе лучше из них эту бяку выкорчевать, конечно.

const86 ★★★★★ ()

MyClass *ms = new MyClass();

BaseClass *ms = new MyClass();

Или

MyClass *ms = new MyClass();
((BaseClass*)ms)->f(0, 10);

andreyu ★★★★★ ()

Потому что это такое дизайн-решение в языке: переопределенные методы скрывают все одноимённые методы родительского класса. Я так понял, так сделано из-за весёлых приключений в стране неявных приведений типов.

ilammy ★★★ ()

нашел в книге. надо поменять код

class MyClass : public BaseClass
{
public:
    using BaseClass::f;
	virtual void f(float e, float f, int a, int b) override {
		std::cout << "MyStorage" << std::endl;
	}
};
lsv ()

Поскольку ответ на свой вопрос вы уже нашли, то нужно указать еще на одно место, которое следует переделать. Голые указатели, ручной вызов new и delete — это зло. Используя их вы будете создавать утечки памяти не только в таких игрушечных примерах, но и в реальном коде. Поэтому вместо:

int main(int argc, char* argv[]) {
	MyClass *ms = new MyClass();
	ms->f(0, 10);
	return 0;
}
Можно было бы написать:
int main() {
	auto ms = std::make_unique<MyClass>();
	ms->f(0, 10);
	return 0;
}
Или, что еще лучше, т.к. вообще не требует работы с динамической памятью, вот так:
int main() {
	MyClass ms;
	ms.f(0, 10);
	return 0;
}

eao197 ★★★★★ ()
class MyClass : public BaseClass
{
public:
        using BaseClass::f;

	virtual void f(float e, float f, int a, int b) override {
		std::cout << "MyStorage" << std::endl;
	}

</thread>

anonymous ()
Ответ на: комментарий от eao197

код, который я привел в вопросе лишь для показа проблемы. реальный код отличен от него на 99%. не буду же я писать сюда половину программы, чтобы народ утомлять лишним чтением?

lsv ()
Ответ на: комментарий от lsv

Люди, которые в малюсеньком примере вместо

MyClass ms;
пишут
MyClass * ms = new MyClass();
да еще и забывают вызывать delete, должны всерьез задуматься: а нужен ли им C++ или лучше продолжать писать на Java/C#/Python/Ruby/etc. А если таки нужно, то имеет смысл вырабатывать в себе правильные привычки с самого начала. Иначе потом код превращается в неподдерживаемое говно мамонта. Проверено неоднократно.

eao197 ★★★★★ ()
Ответ на: комментарий от eao197

а как вызывается виртуальная функция без динамики? а тебе код привести по всем правилам или чтобы понять суть проблемы?

lsv ()
Ответ на: комментарий от lsv

Молодой человек, проштудируйте «Язык программирования C++» Страуструпа. Многие вопросы отпадут сами собой.

Проблема, с которой вы столкнулись, не имеет отношения к тому, как создан экземпляр класса MyClass: статически, на стеке или динамически. Проблема в том, что определение метода f() в MyClass «прячет» объявления f() в BaseClass. Посему компилятор, встретив вызов MyClass::f(), ищет f() среди методов MyClass, а не среди методов BaseClass. Для того, чтобы ввести имена BaseClass::f в область поиска и требуется явно заданная конструкция using BaseClass::f в определении класса MyClass.

При этом, повторюсь, совершенно не имеет значения, как именно создан экземпляр MyClass и через что (ссылку, указатель) вы делаете вызов f() для этого экземпляра.

Что касается «по всем правилам». В C++ есть правило удалять все динамически созданные объекты, т.к. GC в C++ нет и new без delete будет приводить, как минимум, к утечкам памяти. А так же, поскольку в C++ принято освобождать ресурсы в деструкторах, и к утечками других типов ресурсов.

Поэтому, если в C++ коде делается вызов new, то нужно сразу же позаботиться о вызове delete. Самый простой способ сделать это — использовать unique_ptr и make_unique.

Однако, в вашем примере даже это не нужно, т.к. можно создать экземпляр класса MyClass на стеке и он будет автоматически подчищен при выходе из main.

Это, блин, самые азы, которые должны вдалбливаться начинающим C++никам с самого начала. Только вместо того, чтобы учиться азам, некоторые персонажи сначала привыкают говнокодить на C++, потом копаться в своем говнокоде, а потом кричать, что C++ говно.

eao197 ★★★★★ ()
Ответ на: комментарий от eao197

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

Это, блин, самые азы... персонажи сначала привыкают говнокодить.

а ты никогда не ошибаешься?

show me your code, учитель)

lsv ()
Ответ на: комментарий от lsv

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

Т.е. у вас в коде используются голые указатели и явные вызовы new/delete. При этом вы таки пользуетесь компилятором, который поддерживает, как минимум, C++11...

Прелэстно, что тут еще сказать. Вы бы свою спесь поумерили, да послушали, что вам советуют.

а ты никогда не ошибаешься?

Ошибаюсь. Поэтому и рекомендую способы, которые не дают возможности ошибаться.

show me your code, учитель)

Если хотите именно C++ного, то без проблем: вот, например.

eao197 ★★★★★ ()
Ответ на: комментарий от eao197

с чего такой вывод? ты телепат? в коде у меня не используются «голые указатели»; да, компилятор держит с++11;

отвечу специально для тебя и один раз: «код, который я привел в вопросе лишь для показа проблемы. реальный код отличен от него на 99%. не буду же я писать сюда половину программы, чтобы народ утомлять лишним чтением?»

lsv ()
Ответ на: комментарий от lsv

с чего такой вывод? ты телепат?

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

код, который я привел в вопросе лишь для показа проблемы.

Показанный код содержит другие проблемы. Этот код, в совокупности с вашими комментариями (в частности про вызов виртуального метода без динамики) наводит на мысль о том, что знания C++ у вас далеки от минимально необходимых. Собственно, отсюда и советы.

Не хотите к ним прислушиваться — дело ваше.

eao197 ★★★★★ ()

то все работает. а почему?

почему что с++ перегруженное, замуженное г-но, ваш КО. :D :D :D

vtVitus ★★★★★ ()
Ответ на: комментарий от eao197

Люди вам тут ничего не должны, несмотря на ваш самопеар :)

Молодой человек,

ОМГ, седые муди он чу! кряхтение под весом лет, и борода, и благородные седины, и опыт сын ошибок трудных... и на челе морщин патина :)

slackwarrior ★★★★★ ()
Последнее исправление: slackwarrior (всего исправлений: 1)
Ответ на: комментарий от lsv

Щас он тебе ссыль на «самобампающийся» тред со своей поделкой вручет :)

slackwarrior ★★★★★ ()
Ответ на: комментарий от vtVitus

ваш КО-KO-KO. :D :D

Простите, что вы сказали?

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.