Множественное определение одной и той же функции класса в зависимости от нескольких типов одного и того же унаследованного класса? - PullRequest
1 голос
/ 30 марта 2020

Можно ли выполнить множественное определение одной и той же функции класса (полиморфизм) в зависимости от нескольких типов унаследованных классов:

#include <iostream>
#include <vector>
#include <string.h>
//All base A class
class A{
    public:
        int e = 0;
        virtual int GetE() = 0; //to make A virtual
};
class A_A : public A{
    public:
        A_A(){e=1;}
        virtual int GetE(){return e;}
};
class A_B : public A{
    public:
        A_B(){e=2;}
        virtual int GetE(){return e;}
};
//All base B Class
class B{
    public:
        virtual void ActionOnA(A_A& a){a.e = 100;}
        virtual void ActionOnA(A_B& a){a.e = 200;}
        virtual void ActionOnA(A& a){}
};
class B_A : public B{
    public:
        /*
            B_A as the same behaviour of B class but B is virtual
        */
};
class B_B : public B{
    public:
        /*
            B_B do different things on A depending on wich A object is passed
        */
        virtual void ActionOnA(A_A& a){a.e += -100;}
        virtual void ActionOnA(A_B& a){a.e += -200;}
        virtual void ActionOnA(A& a){}
};
//now I create a custom A_* class
class A_C : public A{
    public:
        A_C(){e=90;}
        virtual int GetE(){return e;}
};
//Since A_C is never handled anywhere, I must create a new B_* to handle it
//I want it have the behaviour of B_A in every A class except for A_C
class B_C : public B_A{
    public:
        virtual void ActionOnA(A_C& a){a.e = 0;}
};

int main(int argc, const char *argv[])
{
    std::vector<A*> AllMyA;
    A_A Object1;
    A_B Object2;
    A_C Object3;

    AllMyA.push_back(&Object1);
    AllMyA.push_back(&Object2);
    AllMyA.push_back(&Object3);

    B_A test;
    for(A* a : AllMyA){
        test.ActionOnA(*a);
        std::cout << a->GetE() << '\n';
    }
    /*
        Result should be :
            100
            200
            90
        Result is :
            1
            2
            90
    */

    AllMyA.clear();

    A_A Object4;
    A_B Object5;
    A_C Object6;

    AllMyA.push_back(&Object4);
    AllMyA.push_back(&Object5);
    AllMyA.push_back(&Object6);

    B_B test2;
    for(A* a : AllMyA){
        test2.ActionOnA(*a);
        std::cout << a->GetE() << '\n';
    }
    /*
        Result should be :
            100
            200
            0
        Result is :
            1
            2
            90
    */
}

Этот пример не работает, он всегда вызывает ActionOnA (A & a). Может кто-нибудь объяснить мне, как я могу заставить это работать, зная тот факт, что я не могу сделать static_cast, потому что я не знаю, какой тип A_ * мой A ptr? Разве не существует лучший способ работы? Может с шаблоном?

Заранее спасибо

1 Ответ

1 голос
/ 30 марта 2020

Существует большая разница между функциями ActionOnA и GetE; GetE - это виртуальная функция, поэтому компилятор записывает переход к соответствующей функции в таблице виртуальных функций объекта, которая определяется во время выполнения.

Однако, когда мы смотрим на ActionOnA, компилятору нужно «знать» , какую функцию записывать во время компиляции (она не виртуальная!), поэтому он ставит наиболее подходящую перегрузку функции, которая составляет ActionOnA(A*). Та же проблема возникнет с шаблонами, которые определяются во время компиляции, поэтому он не будет выбирать перегрузку в соответствии со своим типом времени выполнения.

Как писал ChrisMM , вы можете попытайтесь сделать dynamic_cast, который может потерпеть неудачу. Но мне кажется, что проблема немного в другом:

Вы хотите иметь динамическую c функцию в A, которая выполняет допустимую операцию во время выполнения:

virtual void updateE(bool shouldResetE);

В A_A:

void updateE(bool shouldResetE) final
{
    this->E = shouldResetE ? 100 : this->E - 100;
}

Кроме того, настоятельно рекомендуется использовать спецификаторы override и final, поскольку это помогает отлавливать ошибки во время компиляции (override будет предупреждать о неправильном переопределении функции , final будет предупреждать при попытке переопределить эту функцию при наследовании классов). Если A_ * не предназначен для наследования, укажите его с помощью final.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...