Здравствуйте, Eldar9x, Вы писали:
E>Каким образом привести указатель к типу B*?
Если достоверно не известно что за указателем на А скрывается B — нужно использовать dynamic_cast.
Если известно — static_cast, но лично я использую polymorfic_downcast, который в дебаге проверяет что это действительно так.
Здравствуйте, NikeByNike, Вы писали:
NBN>Если достоверно не известно что за указателем на А скрывается B — нужно использовать dynamic_cast. NBN>Если известно — static_cast, но лично я использую polymorfic_downcast, который в дебаге проверяет что это действительно так.
если имелось ввиду
A * a = new C();
dynamic_cast<A*>(a)->do_it();
то это не сработает, все равно вызовется метод класса С — функция виртуальная.
E>получаем "c method"
E>получить указатель типа (A*) легко: E>
E>A * a = new C();
a->>A::do_it(); // "a method"
E>
Выражение a->A::do_it(); не является приведением — это просто вызов функции с явной квалификацией.
E>или E>
E>A * a = new C();
E>a = new A(*A)
a->>do_it(); // "a method"
E>
Это тоже сложно назвать приведением типа указателя — здесь просто напросто создается новый объект типа A (при этом предыдущий объект типа C, на который раньше указывал a, утекает).
E>Каким образом привести указатель к типу B*?
A * a = new C();
B* b = static_cast<B*>(a);//или dynamic_cast
b->do_it();//c method
b->B::bo_it();//b method
NBN>A * a = new C();
NBN>B * b = dynamic_cast<B*>(a);
NBN>if ( b )
NBN>{
b->>B::do_it();
NBN>}
NBN>
понятно. А возможно ли изменить тип указателя на тип B*, после операции:
A * a = new C();
так чтобы, вызов
a->do_it();
приводил к вызову метода класса B? Другими словами, сделать что-то вроде:
A * a = new C();
a = new B(*a); // получили указатель типа B*, с данными от С,
// пусть это и чревато потерей данных.
// Только сделать это не даст компилятор.
лучше озвучте суть проблемы, а то какие то технические детали вами придуманного способа её обхода обсуждаем.
Судя по описанию, можно предложить расширить интерфейс А(добавить doB), либо использовать костыли вроде State паттерна.
E>понятно. А возможно ли изменить тип указателя на тип B*, после операции: E>
E>A * a = new C();
E>
Тип переменной в с++ менять нельзя никак. Можно далее в коде написать что-то вроде:
a = new B();
Если вам нужно полиморфное поведение, меняйте сам объект. Ну или изобретайте какой нить велосипед/городите враппер, что хуже решать вам.
вот пример недо State декоратора:
Здравствуйте, dotidot, Вы писали:
D>лучше озвучте суть проблемы
На самом деле, хотелось узнать, можно ли как то управлять вызовами виртуальных функций. То есть получается, что уже в момент создания объекта по указателю на базовый класс,
A *a = new C();
мы определяем, какая функция будет вызываться для этого объекта в иерархии классов.
А если вдруг окажется, что мне в какой-то момент понадобился вызов виртуальной функции не подразумевающегося класса, а скажем на шаг выше, или даже на два. Отсюда и возникает вопрос, возможно ли каким-то образом манипулировать указателем, уже после того, как объект создан, и тип его уже известен.
То есть, a->do_it() точно известно, что вызовется витуальная функция текущего типа класса.
Как вызвать для ЭТОГО объекта виртуальную функцию ОПРЕДЕЛЕННОГО класса, причем не меняя при этом никаких данных объекта, не меняя его тип итп?
Здравствуйте, Eldar9x, Вы писали:
E>На самом деле, хотелось узнать, можно ли как то управлять вызовами виртуальных функций.
Можно. Есть 2 варианта:
1.неквалифицированный вызов a->do_it() — вызывается final overrider, т.е. в данном случае C::do_it.
2.квалифицированный вызов — вызывается указанный вариант:
B* b = new C();
b->A::do_it();
b->B::do_it()
E>То есть получается, что уже в момент создания объекта по указателю на базовый класс, E>
E>A *a = new C();
E>
"создание объекта по указателю на базовый класс" — бесмыссленая фраза.
E>мы определяем, какая функция будет вызываться для этого объекта в иерархии классов.
Именно — объект имеет свой динамический тип, который невозможно изменить.
E>А если вдруг окажется, что мне в какой-то момент понадобился вызов виртуальной функции не подразумевающегося класса, а скажем на шаг выше, или даже на два. Отсюда и возникает вопрос, возможно ли каким-то образом манипулировать указателем, уже после того, как объект создан, и тип его уже известен.
Указателем манипулировать можно, но динамический тип объекта от этого не изменится.
E>То есть, a->do_it() точно известно, что вызовется витуальная функция текущего типа класса. E>Как вызвать для ЭТОГО объекта виртуальную функцию ОПРЕДЕЛЕННОГО класса, причем не меняя при этом никаких данных объекта, не меняя его тип итп?
Используя явную квалификацию. Если, имея указатель типа A*, и зная, что этот указатель указывает на объект типа C, то для вызова метода B::do_it нужно проделать 2 операции:
1. преобразовать указатель типа A* в указатель типа B* или C*
2. вызвать требуемый метод, используя явную квалификацию
A* a = new C();
B* b = static_casz<B*>(a);
b->B::do_it();
C* c = static_cast<C*>(a);
c->B::do_it();
c->C::do_it();
Здравствуйте, Bell, Вы писали: E>>Как вызвать для ЭТОГО объекта виртуальную функцию ОПРЕДЕЛЕННОГО класса, причем не меняя при этом никаких данных объекта, не меняя его тип итп? B>Используя явную квалификацию. Если, имея указатель типа A*, и зная, что этот указатель указывает на объект типа C, то для вызова метода B::do_it нужно проделать 2 операции: B>1. преобразовать указатель типа A* в указатель типа B* или C* B>2. вызвать требуемый метод, используя явную квалификацию B>
B>A* a = new C();
B>B* b = static_casz<B*>(a);
b->>B::do_it();
B>C* c = static_cast<C*>(a);
c->>B::do_it();
c->>C::do_it();
B>
Теперь все понятно, большое спасибо.
Насколько я понял, невозможно изменить указатель так, чтобы неквалифицированный вызов a->do_it() привел бы к вызову виртуальной функции какого-либо базового класса в иерархии.
Здравствуйте, Eldar9x, Вы писали:
E>Теперь все понятно, большое спасибо. E>Насколько я понял, невозможно изменить указатель так, чтобы неквалифицированный вызов a->do_it() привел бы к вызову виртуальной функции какого-либо базового класса в иерархии.
Правильно. Если do_it переопределена в наследниках, то будет вызван именно вариант из самого нижнего наследника, содержащего переопределение.
ЗЫ
Существует тонкость, связанная с вызовом (прямым или опосредованным) виртуальных функций в конструкторах/деструкторе. Тема эта время от времени всплывает, так что, возможно, тебе тоже будет интересно... Так что поиск в помощь
Здравствуйте, Eldar9x, Вы писали:
E>Каким образом привести указатель к типу B*?
При желании извращаться бесконечно, можно извратиться довольно продвинутым способом.
Я так понимаю, что у тебя есть два метода, работающих с одиними и теми же данными. И тебе хочется так менять указатель, чтобы переключать какой из методов позавётся?
Я тогда немного переформулирую задачу:
class MyRealClass {
// Тут данные и методы, в том числеvoid Method1();
void Method2();
};
Теперь заводим интерфейс, через который мы планируем иметь доступ к нашему объекту:
IMyMethod* p = ( new MyClass )->GetMethod1();
p->Method(); // Method1
p = p->GetMethod2();
p->Method(); // Method2delete p; // Всё хорошо, ничего не утекает :)
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
спасибо, конечно, но такое решение для такого ничтожного вопроса, если честно, это как из пушки по воробьям.
Ну ответ уже найден:
E>Насколько я понял, невозможно изменить указатель так, чтобы неквалифицированный E>вызов a->do_it() привел бы к вызову виртуальной функции какого-либо базового класса E>в иерархии.
Правильно. Если do_it переопределена в наследниках, то будет вызван именно вариант из самого нижнего наследника, содержащего переопределение.