В последнее время я работал над проектом, и дело в том, что мы столкнулись с ситуацией, в которой мы должны иметь возможность делать подобные вещи.CRTP/Macros/Избегайте указателя на производный класс
#define TYPED(Type) \
virtual Type *typedThis() const { return (Type*) this; }
class A {
public:
TYPED(A)
virtual void describe() { std::cout << "I am type A\n"; }
static int x;
};
int A::x = 1;
class B : public A {
public:
TYPED(B)
virtual void describe() { std::cout << "I am type B\n"; }
static int x;
};
int B::x = 2;
int
main(int argc, char** argv)
{
B* b = new B();
A* b2 = b;
b->describe();
b2->describe();
std::cout << b->typedThis()->x << std::endl;
std::cout << b2->typedThis()->x << std::endl; // AQUI DEBERIA DAR 2 !! :c
}
Это, конечно, только пример игрушки. Основная идея того, что мы хотели бы сделать, - определить функцию typedThis(), которая выполняет литье указателя в правильный тип, а затем доступ к правильной переменной x и распечатку 2 вместо 1.
Однако вывод состоит в следующем:
I am type B
I am type B
2
1 //Here should also be 2
что я нахожу очень интересным является то, что виртуальный метод описания(), кажется, работает так, как мы хотим. Поэтому я мог бы сделать вывод о том, что метод typedThis() также работает так, как нам хотелось бы. Но если да, то почему C++ видит этот указатель как A * вместо B *. Если C++ видел этот указатель как B *, тогда он использовал бы правильную переменную x. Может кто-нибудь объяснить это мне?
Я пробовал использовать CRTP, однако я не чувствую, что это облегчит ситуацию, потому что в проекте мы будем использовать много (ЛОТ) разных классов, которые производят между ними постоянно, я видел некоторые статьи о том, как использовать CRTP при наличии множественного наследования, однако они действительно беспорядочны и трудно интегрируются с тем, что мы имеем до сих пор.
Почему должно быть 2, если оно не является виртуальным? Он будет разрешен с базовым классом указателя вместо проверки на любую виртуальную таблицу для решения этой функции. – Raistmaj
pba должен быть виртуальным. – NathanOliver
Да. Поскольку это всего лишь игрушечный пример, я использовал фиктивный метод, который просто распечатывает число. Но в реальном коде мы хотим получить доступ к некоторым атрибутам, которые имеют одинаковое имя между классами. Поэтому предположим, что оба класса A и B имеют статический атрибут x. Затем мы получаем указатель A *, но с указателем экземпляра B. Тогда, если мы хотим получить значение x. Мы получаем значение x класса A, а не класс B.Который в этом примере был бы эквивалентен высказыванию, мы печатаем с использованием метода pba() для A вместо метода pba() из B. – Fertaku