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

Хорошо... предыдущий пример работает нормально... конкретная реализация метода 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 без использования cast, typeid и т. д.?


person Heisenbug    schedule 24.01.2011    source источник
comment
A и B должны быть напечатаны и во втором случае. Вы что-то упустили из своего описания?   -  person vitaut    schedule 24.01.2011
comment
Я проверил ваш код на g++, и он печатает A и B в обоих случаях. Вы случайно не используете OtherClass *?   -  person casablanca    schedule 24.01.2011
comment
class AbstractClass : public Other class должно быть class AbstractClass : public OtherClass   -  person Elalfer    schedule 24.01.2011
comment
Как вы объявляете ptrA и ptrB во втором случае? Такое поведение имеет смысл только в том случае, если у вас есть OtherClass *ptrA.   -  person    schedule 25.01.2011


Ответы (7)


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

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

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

person Grammin    schedule 24.01.2011

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

person Puppy    schedule 24.01.2011

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

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

person Argote    schedule 24.01.2011

Ответ DeadMG, конечно, правильный. Но если вы не можете изменить OtherClass Methode (например, из сторонней библиотеки), вы можете попробовать следующее:

Являются ли указатели ptrA и ptrB типа OtherClass или AbstractClass в нижнем примере?

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

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

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

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

person Elalfer    schedule 24.01.2011

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

person DesignFirst    schedule 24.01.2011

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

 #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.

person Heisenbug    schedule 24.01.2011