Требуются помощь с реализацией трех задач. Думаю над их реализацией больше недели. Я догадываюсь, что здесь нужно использовать полиморфизм. Но как - не могу понять.
Вот они:
Есть некоторый класс, в котором обязательно есть 1 виртуальная функция, которая не работает с данными класса но что-то выводит на экран. Объявление класса есть. Как вызвать эту функцию не используя ее имя?
Есть указатель на объект класса, и через него вызывается функция (p-> F ()). Как не меняя класса обеспечить, чтобы при вызове функции F (), вызывалась не она, а новая моя функция?
Есть класс в котором объявлено функцию и элемент типа int I. через указатель вызывается функция, которая возвращает элемент. и он выводится на экран.
cout << p-> GetI ();
Как сделать, чтобы при вызове функции GetI ()
вызывалась не она, а новая моя функция, которая изменит элемент int I
умножив его на 10 и выведет на экран?
Добавлено. Я уточнил 2 и 3 задания.
int
. Через указатель на объект класса вызывается метод, который возвращает значение элемента int
. Как не меняя реализацию класса обеспечить , чтобы при вызове метода через указатель вызывался не он, а моя глобальная функция, которая изменит элемент пита int
умножив его на 10?Важно - наследование использовать нельзя; соответственно нельзя создавать новых классов.
int
. Через указатель на объект класса вызывается метод, который возвращает значение элемента int
. Как не меняя реализацию класса обеспечить , чтобы при вызове метода через указатель вызывался не он, а моя глобальная функция.Важно - наследование использовать нельзя; соответственно нельзя создавать новых классов.
Задания сформулированы ужасно, мои сочувствия вам.
1) Что означает «не используя ей имя»? Чтобы вызвать функцию, надо указать её имя в той или иной форме. То, работает функция с данными класса или нет, полностью несущественно.
Можно произвести от данного класса производный класс, не переопределять в нём нужную функцию, в написать другую функцию-обёртку.
class Given
{
public:
virtual void func() { cout << "Done" << endl; }
};
class Derived : public Given
{
public:
void wrapper() { func(); }
}
// вызов без использования имени
Derived d;
d.wrapper();
Можно тупо заменить вызов макросом:
#define WRAP() func()
Given g;
g.WRAP();
По существу отличающихся корректных способов не вижу.
2) Если функция виртуальная, породите класс от данного и перекройте функцию.
class Given
{
public:
virtual string func() { return "Given"; }
};
class Derived : public Given
{
public:
virtual string func() { return "Overridden"; }
}
Given* p = new Derived;
cout << p->func();
Если нет, невозможно. Хотя подход с макросом пройдёт, если есть хоть какая-то виртуальная функция.
3) То же самое. Если функция GetI
виртуальная, породите класс от данного и перекройте функцию. Если нет, корректно сделать невозможно.
1) Получите указатель на таблицу виртуальных функций. Вызовите функцию прямо по адресу.
Пример кода:
#include <iostream>
class A {
public:
virtual void func() { std::cout << "Hello\r\n"; }
};
typedef void (*func_type)();
int main()
{
A* a = new A;
/*a->func();*/ // не вызываем по имени!
// указатель на таблицу виртуальных функций
func_type* _vptr_table = *reinterpret_cast<func_type**>( a );
// указатель на первую и единственную функцию в таблице
func_type f = _vptr_table[0];
// вызываем по указателю!
f();
delete a;
return 0;
}
Чтобы понять, что такое таблица виртуальных функций: Таблица виртуальных функций на Wikipedia
По 2) и 3) Согласен с @VladD. Унаследоваться и перекрыть виртуальную функцию.
Это не ответ.
Из ответа atwice:
Используя reinterpret_cast<тип*> мы получаем все указатели на переменные или виртуальные методы данного типа, которые есть в структуре. Они идут по порядку их объявления.
Важный отрывок из условия задачи:
Есть некоторый класс, в котором обязательно есть 1
виртуальная функция, которая не
работает с данными класса но что-то
выводит на экран
Если это "литературно" разобрать, то
class A
{
public:
virtual void func() { std::cout << "Hello\r\n"; } // одна обязательная виртуальная функция
void func2(); // не обязательная не виртуальная функция
virtual void func3() { std::cout << "Hello3\r\n"; } // не обязательная вторая виртуальная функция
int D; // данные класса с которыми не работает func(). Значит они есть.
};
Правильный ответ atwice. Но если поменять местами func3 и func то ответ atwice не правильный. Так как будет вызвана func3().
Но если мы знаем в какой последовательности будут расположены виртуальные функции в объявлении класса, то ответ atwice всё же будет правильным, достаточно будет изменить _vptr_table[0] на _vptr_table[n] в зависимости от порядка расположения виртуальных функций с одинаковым прототипом, при условии поддержки данного механизма в конкретной версии среды разработки и соблюдении необходимых настроек компиляции.
Вывод:
Зная прототип этой обязательной виртуальной функции и порядок расположения в структуре виртуальных функций с таким же прототипом, мы можем вызвать эту функцию не зная её имени, используя таблицу виртуальных функций.
Однако если условие задачи автора на самом деле иное, и предполагается что нельзя делать вызов функции по имени которое объявлено в классе, то правильными будут ответы VladD и perfect.
По поводу первого пункта в вопросе. Проанализируйте это:
#include <iostream>
using namespace std;
class C{
public:
virtual void draw(){ // настоящее имя
cout << "hello" << endl;
}
};
int main() {
C * theClass = new C;
void (C::*blabla)();
blabla = &C::draw;
(theClass->*blabla)(); // уже ненастоящее имя
delete theClass;
return 0;
}
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Только начал изучать С++, возникла сложностьНеобходимо присвоить определенному элементу массива значение
Не могу понять как заставить генератор случайных чисел давать дробные значенияПробовал сделать так