同一个类函数的多个定义取决于同一个继承类的多个类型?

Posted

技术标签:

【中文标题】同一个类函数的多个定义取决于同一个继承类的多个类型?【英文标题】:Multiple definition of same class function depending on multiple type of the same inherited class? 【发布时间】:2020-03-30 16:49:07 【问题描述】:

是否可以根据继承类的多种类型对同一类函数(多态性)进行多次定义:

#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 behavior of B class but B is virtual
        */
;
class B_B : public B
    public:
        /*
            B_B do different things on A depending on which 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 behavior 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 ptr 是哪种类型的 A_*? 难道不存在更好的工作方式吗?也许有模板?

【问题讨论】:

你可以使用dynamic_cast @ChrisMM 不,它不起作用,因为我应该不知道它是 A 的继承类型(也许稍后,此代码将在 lib 中,用户将能够重新定义自己的 A 和 B 类)。 我认为你并没有真正理解运行时类型和编译类型之间的区别。正如 Karek 提到的,在ActionOnA 的情况下,它基于静态(编译时)类型;不是运行时类型。所以你需要一个dynamic_cast 来调用相应的函数。 【参考方案1】:

函数ActionOnAGetE有很大区别; GetE是一个虚函数,因此编译器会在对象的虚函数表中写下一个跳转到对应的函数,这个跳转是在运行时确定的。

但是,当我们查看ActionOnA时,编译器需要“知道”在编译时写下什么函数(它不是虚拟的!),因此,它放置了最合适的函数重载,即ActionOnA(A*)。模板也会出现同样的问题,模板是在编译时确定的,因此不会根据运行时类型选择重载。

正如ChrisMM 所写,您可以尝试制作可能会失败的dynamic_cast。但在我看来问题有点不同:

您希望在 A 中有一个动态函数,它可以在运行时进行有效操作:

virtual void updateE(bool shouldResetE);

在 A_A 中:

void updateE(bool shouldResetE) final

    this->E = shouldResetE ? 100 : this->E - 100;

此外,强烈建议同时使用 overridefinal 说明符,因为它有助于在编译时捕获错误(override 会在未正确覆盖函数时发出警告,final 会在尝试覆盖时发出警告在继承类上覆盖此函数)。如果不是要继承 A_*,请使用 final 指定它。

【讨论】:

以上是关于同一个类函数的多个定义取决于同一个继承类的多个类型?的主要内容,如果未能解决你的问题,请参考以下文章

关于类继承的构造与析构调用分析

201771010143 张云飞《面向对象程序设计(java)》第六章学习总结

java类的继承-----继承的定义

关于泛型

多个类型/类的HQL查询

纯虚函数的 C++ 继承