C ++ переопределить виртуальный метод с абстрактным классом в качестве параметра

У меня есть следующий абстрактный класс

class A {
public:
virtual void foo(A* a) = 0;
}

и несколько классов, наследующих от этого класса. например

class B : public A {
public:
void foo(A* a); // implementation in a separete file
}

Тем не менее, я хочу только класс B принять себя в качестве аргумента в foo

void foo(B* b);

Возможно ли сделать это в C ++?
Я рассмотрел шаблон, но синтаксис допускает слишком большую гибкость. Можно написать class B: public A<B>, но я хочу ошибку компилятора с class B: public A<C>,

— Редактировать —

Похоже, мое использование абстрактного класса не оправдано. Позвольте мне прояснить мою ситуацию.

Я использую полиморфное поведение A в отдельной функции. В дополнение к этому, я хочу определить функцию, которая принимает аргумент того же типа, что и приведенный выше. Я пытаюсь написать функцию, которая определяет расстояние между двумя объектами производного класса. Расстояние определяется только между объектами одного класса (b1 а также b2, или же c1 а также c2, но нет b1 а также c2). Я также хотел бы получить доступ к этой функции расстояния в общем виде, насколько это возможно.

— Редактировать 2—

Кассио показал, почему невозможно выполнить проверку на основе компилятора. Решение ZAR добавляет немного больше структуры в код с проверкой ошибок во время выполнения.

-1

Решение

Я понимаю, что ваш вопрос больше о синтаксисе. То, что у вас есть, правильно, просто передайте объект типа B. В определении все равно будет сказано A, но он будет рад взять производный класс. Вам не нужно никакого специального определения для этого.

class A {
public:
virtual void foo(A* a) = 0;
};

class B : public A {
public:
void foo(A* a)
{
if (dynamic_cast<B*> (a) == NULL)
std::cout << "wrong type, expecting type B\r\n";
}
};

class C : public A {
public:
void foo(A* a)
{
if (dynamic_cast<C*> (a) == NULL)
std::cout << "wrong type, expecting type C\r\n";
}
};

int main()
{
B * b1 = new B;
B * b2 = new B;

C * c1 = new C;
C * c2 = new C;

b2->foo(c1); // bad

c1->foo(b1); // bad

b2->foo(b1); // good

delete b1;
delete b2;
delete c1;
delete c2;
}

смотрите также dynamic_cast.

1

Другие решения

Это не то virtual для.

virtual есть, чтобы включить полиморфное поведение. В основном, чтобы включить это:

struct A {virtual void foo()=0;};

// Two different "behaviors" for the same "A"struct B {void foo() override{}};
struct C {void foo() override{}};

// forgive the leak, this is just to prove a point.
A* b = new B();
A* c = new C();
b->foo(); // Will call B::foo, even though this is a pointer to "A"c->foo(); // Will call C::foo, even though this is a pointer to "A"

То, как вы пытаетесь его использовать, вы теряете это преимущество и просто получаете производительность виртуальных функций даром. Тот факт, что создание экземпляра класса, который не реализует какую-либо чисто виртуальную функцию, является ошибкой, просто предотвращает плохо сформированные программы.

Если вы хотите убедиться, B реализует некоторый интерфейс, просто используйте этот интерфейс где-нибудь. Если B не реализует это, вы получите ошибку компилятора, которую вы ищете:

class B {};

template<typename T> void call_foo(T* v1, T* v2) {
v1->foo(&v2);
}

B b1;
B b2;
b1.foo(&b2); // error
call_foo(&b1, &b2); // error

Затем, чтобы избавиться от ошибки, вы можете просто реализовать функцию. нет virtual необходимо:

class B {
void foo(B*) {/*do something*/}
};

B b1;
B b2;
b1.foo(&b2); // ok
call_foo(&b1, &b2); // ok

Но почему я не могу использовать виртуальную функцию для этого?

Представьте себе следующий сценарий:

struct A {virtual void foo(A*)=0;};

// Imagine if the language allowed this:
struct B {void foo(B*) override{}};
struct C {void foo(C*) override{}};

// (...)

// I create a vector of objects, and insert three of them in this vector.
std::vector<A*> objects;

// Note that foo is well-defined only for the first two.
objects.push_back(new B();)
objects.push_back(new B();)
objects.push_back(new C();)

// Then I shuffle the vector
std::shuffle(objects.begin(), objects.end());

// At least one of these three lines should give a compiler error.
// Which one(s)?
objects[0]->foo(objects[1]);
objects[0]->foo(objects[2]);
objects[1]->foo(objects[2]);

Но мне нужно, чтобы функция была виртуальной, и мне нужна безопасность типов!

Виртуальные функции являются механизмом выполнения. Вам нужно будет проверить тип во время выполнения. ответ зара уже хорошо это освещает, так что я не буду вдаваться в подробности. Подводя итог: просто dynamic_cast в тип, который вы хотите, и если приведение возвращает nullptr, у вас неправильный тип. Затем вы можете сгенерировать исключение или распечатать диагностическое сообщение.

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector