Прямое объявление и typeid
-
20-09-2019 - |
Вопрос
Я хотел бы проверить тип суперкласса A
против типа подкласса B
(с помощью метода внутри суперкласса A
, так что B
унаследует его).
Вот что, как я думал, помогло (то есть использование прямого объявления):
#include <iostream>
#include <typeinfo>
using namespace std;
class B;
class A {
public:
int i_;
void Check () {
if (typeid (*this) == typeid (B))
cout << "True: Same type as B." << endl;
else
cout << "False: Not the same type as B." << endl;
}
};
class B : public A {
public:
double d_;
};
int main () {
A a;
B b;
a.Check (); // should be false
b.Check (); // should be true
return 0;
}
Однако этот код не компилируется.Ошибка, которую я получаю, это:
main.cc: In member function ‘void A::Check()’:
main.cc:12: error: invalid use of incomplete type ‘struct B’
main.cc:6: error: forward declaration of ‘struct B’
Как я мог бы решить эту проблему?
Решение
Я думаю, что проблема, которую вы пытаетесь решить, гораздо лучше решается виртуальным методом:
class A
{
public:
virtual bool Check() { return false; };
}
class B : public A
{
public:
// override A::Check()
virtual bool Check() { return true; };
}
Методам в базовом классе A не нужно знать, является ли объект "действительно" A или a B.Это нарушение основных принципов объектно-ориентированного проектирования.Если поведение должно измениться, когда объект является B, то это поведение должно быть определено в B и обрабатываться вызовами виртуальных методов.
Другие советы
Просто переместите определение Check() из тела:
#include <iostream>
#include <typeinfo>
using namespace std;
class B;
class A {
public:
int i_;
void Check ();
};
class B : public A {
public:
double d_;
};
void A::Check () {
if (typeid (*this) == typeid (B))
cout << "True: Same type as B." << endl;
else
cout << "False: Not the same type as B." << endl;
}
int main () {
A a;
B b;
a.Check (); // should be false
b.Check (); // should be true
return 0;
}
Одним из способов было бы извлечь определение Check
из определения класса, так что B
определяется, когда компилятор переходит к определению функции.
class A {
//...
void Check();
//...
};
class B { /* ... */ };
void A::Check() {
//...
}
Переместите ваше определение проверки ниже вашего объявления класса B.
Просто переместите тело функции после объявления B.
#include <iostream>
#include <typeinfo>
struct A
{
int i_;
void Check();
};
struct B : A
{
double d_;
};
void A::Check()
{
using namespace std;
if (typeid (*this) == typeid (B))
{
cout << "True: Same type as B." << endl;
}
else
{
cout << "False: Not the same type as B." << endl;
}
}
int main()
{
A a;
B b;
a.Check(); // should be false
b.Check(); // should be true
return 0;
}
Привет, даже если вы поместите определение A::Check за пределы класса, результат будет не таким, как вы ожидаете.Это связано с тем, что объект B преобразуется в объект A в методе, поэтому это указывает на объект A, поэтому идентификаторы типов всегда разные.Чтобы решить эту проблему, объявите метод virtual.
Однако я все еще не понимаю, почему вы хотите выполнить такой тест O_o ??И, как сказал Кадакер, это не очень хорошая практика