Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/133.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何从基类中的派生类调用函数?_C++_Class_Oop_Object_Inheritance - Fatal编程技术网

C++ 如何从基类中的派生类调用函数?

C++ 如何从基类中的派生类调用函数?,c++,class,oop,object,inheritance,C++,Class,Oop,Object,Inheritance,我花了好几个小时上网,但没有一个像我一样有同样的问题。基本上,我有一个名为MainShop的基类,它有3个派生类,分别是剑店、咒语书店和弓箭店。我希望基类能够从一个派生类调用函数,但无论我做什么,它似乎都不起作用! 这是我的密码: #include "MainShop.h" //BaseClass cpp void MainShop::EnterShop(Hero& hero) { //Display Choices switch (choice)

我花了好几个小时上网,但没有一个像我一样有同样的问题。基本上,我有一个名为MainShop的基类,它有3个派生类,分别是剑店、咒语书店和弓箭店。我希望基类能够从一个派生类调用函数,但无论我做什么,它似乎都不起作用! 这是我的密码:

#include "MainShop.h"
//BaseClass cpp

void MainShop::EnterShop(Hero& hero)
{
    //Display Choices
        switch (choice)
        {
            //Swords
            case 1: SwordShop::soldierShop(hero);//DOES NOT WORK!!
                        break;
            case 2: SpellBookShop::MageShop(hero);//Staffs
                        break;
            case 3: BowShop::ArcherShop(hero);//Bows
                        break;
            default: cout << "Error!, Please try again.";
                        MainShop::EnterShop(hero);


        }
}

我想你可以试试这样的东西:

Derived* derived = dynamic_cast<Derived*>(this);
if (derived) {
    // this is of Derived type
} else {
    // this is of base type but not Derived
}

更好的可读性,更少出错,更理智。

我想你可以尝试以下方法:

Derived* derived = dynamic_cast<Derived*>(this);
if (derived) {
    // this is of Derived type
} else {
    // this is of base type but not Derived
}

更好的可读性,更少出错,更理智。

像这样的东西怎么样? 显然,您必须实现
.shop()
功能:

MainShop *ms;
switch(input){
    case 1:
    ms = new soldierShop(); break;
    case 2:
    ms = new MageShop(); break
    case 3:
    ms = new ArcherShop(); break;
}
ms.shop();

像这样的怎么样? 显然,您必须实现
.shop()
功能:

MainShop *ms;
switch(input){
    case 1:
    ms = new soldierShop(); break;
    case 2:
    ms = new MageShop(); break
    case 3:
    ms = new ArcherShop(); break;
}
ms.shop();

通常有两个选项用于实现所需的功能:

  • 使用dynamic_cast将
    这个
    指针提升到所需的派生类型,并在cast成功时调用所需的任何函数
  • 将模板化基类与奇怪的循环模板模式结合使用-基本上,将所需的派生类型作为模板参数传递给基类()

  • 通常有两个选项用于实现所需的功能:

  • 使用dynamic_cast将
    这个
    指针提升到所需的派生类型,并在cast成功时调用所需的任何函数
  • 将模板化基类与奇怪的循环模板模式结合使用-基本上,将所需的派生类型作为模板参数传递给基类()
  • 由于运行时开销和将来的维护等原因,在超类方法中选择特定的子类实例(例如通过
    动态\u cast
    )不是一个好的设计

    您可以将这种切换案例逻辑的负担转移到虚拟函数上,这些虚拟函数由语言设计,通过基类指针/引用调用特定实例

    例如:

    class MainShop
    {
    public:
       virtual void EnterShop(Hero &hero) = 0;
    };
    
    class SwordShop: public MainShop
    {
       void EnterShop(Hero &hero)
       {
          soldierShop(hero);
       }
    };
    
    class SpellBookShop: public MainShop
    {
       void EnterShop(Hero &hero)
       {
          MageShop(hero);
       }
    };
    
    int main()
    {
       ...
       MainShop *shop = new SwordShop;
       // calling soldierShop
       shop->EnterShop(hero);
       ..
       shop = new SpellBookShop;
       // calling MageShop
       shop->EnterShop(hero);
       ...
    }
    
    由于运行时开销和将来的维护等原因,在超类方法中选择特定的子类实例(例如通过
    动态\u cast
    )不是一个好的设计

    您可以将这种切换案例逻辑的负担转移到虚拟函数上,这些虚拟函数由语言设计,通过基类指针/引用调用特定实例

    例如:

    class MainShop
    {
    public:
       virtual void EnterShop(Hero &hero) = 0;
    };
    
    class SwordShop: public MainShop
    {
       void EnterShop(Hero &hero)
       {
          soldierShop(hero);
       }
    };
    
    class SpellBookShop: public MainShop
    {
       void EnterShop(Hero &hero)
       {
          MageShop(hero);
       }
    };
    
    int main()
    {
       ...
       MainShop *shop = new SwordShop;
       // calling soldierShop
       shop->EnterShop(hero);
       ..
       shop = new SpellBookShop;
       // calling MageShop
       shop->EnterShop(hero);
       ...
    }
    

    如果您需要从任何shop对象(Swarshop等)调用EnterShop,那么重写基类中的虚拟函数就是一种方法

    class MainShop
    {
         ...
         virtual void process_hero(Hero& hero)
         {
              // add default implementation or set as pure virtual
         }
         ...
    };
    
    void MainShop::EnterShop(Hero& hero)
    {
        process_hero(hero);
    }
    
    class SwordShop: public MainShop
    {
    public:
        void process_hero(hero)
        {
            soldierShop(hero);
        }
    };
    
    ...
    
    但是,在我看来,似乎需要一个管理器对象根据“choice”变量调用函数。如果是这种情况,请使用组合而不是继承


    如果您需要从任何shop对象(Swarshop等)调用EnterShop,那么重写基类中的虚拟函数就是一种方法

    class MainShop
    {
         ...
         virtual void process_hero(Hero& hero)
         {
              // add default implementation or set as pure virtual
         }
         ...
    };
    
    void MainShop::EnterShop(Hero& hero)
    {
        process_hero(hero);
    }
    
    class SwordShop: public MainShop
    {
    public:
        void process_hero(hero)
        {
            soldierShop(hero);
        }
    };
    
    ...
    
    但是,在我看来,似乎需要一个管理器对象根据“choice”变量调用函数。如果是这种情况,请使用组合而不是继承


    这就是虚拟函数的用途。是的,拿着一个指向基类的指针,只需调用
    .shop()
    我认为,您似乎采用结构化的OO方法来构建虚拟函数是很好的,只要您觉得您正在学习或朝着一个目标前进,您肯定应该继续沿着这条道路前进。然而,从长远来看,我的经验是继承和多态性会导致程序不灵活和逻辑重复,尤其是当项目变得更大时。我有过更紧凑、更灵活的程序,具有类型特征和组合。诚然,进入的门槛更高,所以我说现在继续走这条路不是个坏主意。这就是虚拟函数的用途。是的,拿一个指向基类的指针,只需调用
    .shop()
    我认为,您似乎采用结构化的OO方法进行构建,这是一件好事,只要您觉得自己正在学习或朝着一个目标前进,您肯定应该继续走这条路。然而,从长远来看,我的经验是继承和多态性会导致程序不灵活和逻辑重复,尤其是当项目变得更大时。我有过更紧凑、更灵活的程序,具有类型特征和组合。诚然,进入的门槛更高,所以我说现在继续走这条路不是个坏主意。或者虚拟功能?不是虚拟函数无法控制调用哪个派生实例。在很多情况下,你需要调用一些特定的东西(OP可能一直在问这个问题)。99%的人肯定OP需要这样做,这是因为糟糕的设计。OP需要一个虚拟函数,如果不是,则需要重构。如果你不同意我的观点,我强烈建议你解释一下你的解决方案是好的做法,否则答案很可能会误导你?如果我选择了2,我将不得不改变整个项目,而且我并不是真正的C++经验者,所以我要花很长时间才能掌握它。然而,选项1看起来很有趣。你能给我一个如何使用选项1的例子吗?我同意这不是OP问题的解决方案,但我决定放弃-1,因为从技术上讲,这些是“在基类内调用派生类的函数”或虚拟函数的方法。不可以虚拟函数无法控制调用哪个派生实例。在很多情况下,你需要调用一些特定的东西(OP可能一直在问这个问题)。99%的人肯定OP需要这样做,这是因为糟糕的设计。OP需要一个虚拟函数,如果不是,则需要重构。如果你不同意我的观点,我强烈建议你解释一下你的解决方案是好的做法,否则答案很可能会误导你?如果我选择了2,我将不得不改变整个项目,而且我并不是真正的C++经验者,所以我要花很长时间才能掌握它。选择