2011-01-24 2 views
2

У меня проблема с правильной обработкой метода переопределения, где присутствует абстрактный класс внутри моей иерархии классов. Попробую объяснить:C++ и наследование в абстрактных классах

class AbstractClass{ 
public: 
    virtual void anyMethod() = 0; 
}; 

class A : public AbstractClass { 
    void anyMethod() { 
     // A implementation of anyMethod 
     cout << "A"; 
    } 
}; 

class B : public AbstractClass { 
    void anyMethod() { 
     // B implementation of anyMethod 
     cout << "B"; 
    } 
}; 

AbstractClass *ptrA, *ptrB; 

ptrA = new A(); 
ptrB = new B(); 
ptrA->anyMethod(); //prints A 
ptrB->anyMethod(); //prints B 

Ok..previous пример отлично работает .. конкретная реализация метода anyMethod AbstractClass будет вызываться во время выполнения. Но AbstractClass является производным от другого базового класса, который имеет метод не виртуальный под названием anyMethod:

class OtherClass { 
public: 
    void anyMethod() { 
     cout << "OtherClass"; 
    } 
}; 

class AbstractClass : public OtherClass { 
public: 
    virtual void anyMethod() = 0; 
}; 

//A and B declared the same way as described before. 

Теперь, если я попробовать что-то вроде этого:

ptrA = new A(); 
ptrB = new B(); 
ptrA->anyMethod(); //prints OtherClass 
ptrB->anyMethod(); //prints OtherClass 

Что я непонимание? Есть ли какое-либо решение для печати ptrA и ptrB A и B без использования литых, тиреидных и т. Д.?

+0

Отформатируйте свой код – Elalfer

+3

A и B также должны быть напечатаны во втором случае. Вы что-то упустили из своего описания? – vitaut

+3

Я проверил ваш код на g ++, и он печатает A и B в обоих случаях. Используете ли вы 'OtherClass * '? – casablanca

ответ

0

спасибо за ответы .. помог мне много разобраться в проблеме. Фактически я опубликовал неправильный код, потому что я не понимал настоящую проблему. В любом случае, я думаю, что частично решил свою проблему. Вот код:

#include <iostream> 

`` using namespace std; 

class Other{ 

public: 

void foo(){ 
     cout << "Other\n"; 
} 

void foo(int a){} 
}; 

class Abstract : public Other{ 

public: 
virtual void foo() {}; 
virtual void foo(int c){ 
     Other::foo(c); 
} 
}; 

class A : public Abstract{ 

public: 

void foo(){ 
     cout << "A\n"; 
} 
}; 

class B : public Abstract{ 

public: 

void foo(){ 
     cout << "B\n"; 
} 
}; 
int main(){ 

cout << "main\n"; 

Abstract * ptrA = new A(); 
Abstract * ptrB = new B(); 

Other *o = new Other(); 
o->foo(); 

ptrA->foo(); 
ptrB->foo(); 
ptrB->foo(3); //can't no more use the method foo with different signatures implemented in the base class Other, unless I explicitly redefined in the class Abstract 
dynamic_cast<Other*>(ptrB)->foo(3);//can't dynamic_cast from derived to base 

Я делал две ошибки:

  1. В моем реальном коде (не упрощенная версия размещена раньше) я забыл объявить виртуальный функции Foo()

  2. Даже объявление виртуального было недостаточно. Фактически все реализации этой функции должны быть обернуты внутри класса Abstract, чтобы стать видимыми для подклассов A и b. Иначе не компиляция.

Я не знаю, может ли это быть чистым решением. Фактически таким образом мне нужно обернуть все подписи метода foo.

2

Если anyMethod был объявлен виртуальным в базовом классе, к которому у вас есть указатель или ссылка, то должен быть просмотрен практически и правильно напечатать A и B. Если это не так, то вы ничего не можете сделать (не изменяя его, чтобы быть виртуальным).

5

Почему бы вам не сделать:

class OtherClass 
{ 
    public: 
    virtual void anyMethod() 
    { 
     cout << "OtherClass"; 
    }; 
} 

Это должно решить ваши проблемы

2

Я думаю, что если метод в OtherClass, что вы хотите переопределить в A и B не является виртуальным, то переопределение не является неявным.

Я считаю, что есть способ Явно переопределить функции, посмотреть на это.

1

Ответы DeadMGs, конечно, правильные. Но, если вы не можете изменить OtherClass Methode (например, это от Lib третьей стороны), вы можете попробовать это:

ли указатели ptrA и ptrB типа OtherClass или AbstractClass в вашем нижнем примере?

Если они OtherClass Я бы ожидал описанного вами поведения. Вы можете попробовать литье указатель на AbstractClass затем:

dynamic_cast<AbstractClass*>(ptrA)->anyMethod();

+0

Точно .. OtherClass находится в третьей стороне библиотеки, которую я не могу изменить подписи. Я заметил, что мне не хватало объявления виртуальной anyFunction в AbstractClass (извините, но я опубликовал очень упрощенную версию моего кода). Теперь я попробовал это решение, но проблема в том, что в OtherClass anyFunction имеет несколько разных подписей. Кажется, они создают некоторые конфликты, если я не обновляю все это в AbstractClass. Я сделаю некоторые тесты и отправлю более подробный вопрос позже. Спасибо всем – Heisenbug

1

Насколько я могу видеть из кода OtherClass::anyMethod() не является виртуальным и уже реализованы. Он должен работать, как вы описали, если вы определили его как virtual

0

Я думаю, что ваше заявление для второго случая: ДругоеClass * ptrA; а не AbstractClass * ptrA; , если вы заявили как первый случай, нет проблем, потому что метод является виртуальным, но если вы объявляете его как OtherClass, компилятор не найдет виртуального и не привязается к адресу этого метода, не используя vtble.

Смежные вопросы