寻找大型 switch-case 和 if-else 结构的最有效方法

huangapple go评论59阅读模式
英文:

Finding most efficient method for large switch-case and if-else

问题

I've translated the code for you:

我正在学习面向对象编程(OOP),我发现可以使用多态性(polymorphism)来替代switch-case和if-else。但我仍然想知道如何以最高效的方式实现这一点。以下是我用于管理5个不同类的信息的管理类:

class Manage
{
private:
    Human *List[100];
    int iObject_num;
public:
    Manage(){
        iObject_num=0;
    }
    ~Manage(){
        delete List;
    }
    void vInList()
    {
        int choice;
            do
                {
                    Menu(); //菜单有6个选项
                    fflush(stdin);
                    cin>>choice;
                    switch(choice)
                    {
                    case 1:{
                        List[iObject_num]= new Student;
                        List[iObject_num]->vInPrivate(); // 输入基类的保护信息
                        List[iObject_num]->vIn();// 输入每个子类的私有信息
                        iObject_num++;
                        break;}
                    case 2:{
                        List[iObject_num]= new Undergrad;
                        List[iObject_num]->vInPrivate();
                        List[iObject_num]->vIn();
                        iObject_num++;
                        break;}
                    case 3:{
                        List[iObject_num]= new Worker;
                        List[iObject_num]->vInPrivate();
                        List[iObject_num]->vIn();
                        iObject_num++;
                        break;}
                    case 4:{
                        List[iObject_num]= new Actor;
                        List[iObject_num]->vInPrivate();
                        List[iObject_num]->vIn();
                        iObject_num++;
                        break;}
                    case 5:{
                        List[iObject_num]= new Musician;
                        List[iObject_num]->vInPrivate();
                        List[iObject_num]->vIn();
                        iObject_num++;
                        break;}
                    case 0:
                        cout<<"正在退出...\n";
                        break;
                    default:
                        cout<<"无效!\n";
                    }
                } while(choice!=0);

    };
    void vOutList(){
        cout<<"输入的总数: "<<iObject_num<<"\n";
        for (int i=0;i<iObject_num;i++)
        {
            List[i]->vOutPrivate();
            List[i]->vOut();
            cout<<"\n";
        }
    }
};

If you have any specific questions or need further assistance, please feel free to ask.

英文:

I'm learning OOP and I found that you can use polymophism to replace switch-case and if-else. But I still wonder how to do that most efficiently. Here is my manage class for managing info of 5 different class:

class Manage
{
private:
    Human *List[100];
    int iObject_num;
public:
    Manage(){
        iObject_num=0;
    }
    ~Manage(){
        delete List;
    }
    void vInList()
    {
        int choice;
            do
                {
                    Menu(); //the menu has 6 choices
                    fflush(stdin);
                    cin&gt;&gt;choice;
                    switch(choice)
                    {
                    case 1:{
                        List[iObject_num]= new Student;
                        List[iObject_num]-&gt;vInPrivate(); // input the protected info of base class
                        List[iObject_num]-&gt;vIn();// input the private of each child class
                        iObject_num++;
                        break;}
                    case 2:{
                        List[iObject_num]= new Undergrad;
                        List[iObject_num]-&gt;vInPrivate();
                        List[iObject_num]-&gt;vIn();
                        iObject_num++;
                        break;}
                    case 3:{
                        List[iObject_num]= new Worker;
                        List[iObject_num]-&gt;vInPrivate();
                        List[iObject_num]-&gt;vIn();
                        iObject_num++;
                        break;}
                    case 4:{
                        List[iObject_num]= new Actor;
                        List[iObject_num]-&gt;vInPrivate();
                        List[iObject_num]-&gt;vIn();
                        iObject_num++;
                        break;}
                    case 5:{
                        List[iObject_num]= new Musician;
                        List[iObject_num]-&gt;vInPrivate();
                        List[iObject_num]-&gt;vIn();
                        iObject_num++;
                        break;}
                    case 0:
                        cout&lt;&lt;&quot;Exiting...\n&quot;;
                        break;
                    default:
                        cout&lt;&lt;&quot;Invalid!\n&quot;;
                    }
                } while(choice!=0);

    };
    void vOutList(){
        cout&lt;&lt;&quot;Total number of input: &quot;&lt;&lt;iObject_num&lt;&lt;&quot;\n&quot;;
        for (int i=0;i&lt;iObject_num;i++)
        {
            List[i]-&gt;vOutPrivate();
            List[i]-&gt;vOut();
            cout&lt;&lt;&quot;\n&quot;;
        }
    }
};

I've been searching for answer but most of them all told the same thing: override the virtual function. I've already do that as you can see, but if there's more than 5 classes, I will have to do switch-case more than 5 times to call each class' function?

答案1

得分: 1

你可以创建一个工厂,比如 HumanFactory

```cpp
class HumanFactory
{
public:
    virtual Human* createHuman() = 0;
    virtual ~HumanFactory() {}
};

class StudentFactory : public HumanFactory
{
public:
    Human* createHuman() override { return new Student; }
};

所有具体的人类都可以添加到列表中

class Manage
{
private:
    std::vector<Human*> humans;
    std::vector<HumanFactory*> factories;
    
// 注册工厂 
void registerFactory(HumanFactory* factory)
    {
        factories.push_back(factory);
    }

void vInList()
    {
        int choice;
        do
        {
            Menu(); // 菜单有6个选项
            std::cin >> choice;

            if (choice >= 1 && choice <= factories.size())
            {
                Human* human = factories[choice - 1]->createHuman();
                human->vInPrivate();
                human->vIn();
                humans.push_back(human);
            }
            else if (choice != 0)
            {
                std::cout << "无效选择!\n";
            }
        } while (choice != 0);
    }

int main()
{
    Manage manager;
    manager.registerFactory(new StudentFactory());
    // 根据需要注册其他工厂

    manager.vInList();
    manager.vOutList();

    return 0;
}

我提供了代码,虽然没有完全完成,但我认为会给你一个如何替代 switch 的思路。

英文:

You can create factory for example HumanFactory

class HumanFactory
{
public:
virtual Human* createHuman() = 0;
virtual ~HumanFactory() {}
};
class StudentFactory : public HumanFactory
{
public:
Human* createHuman() override { return new Student; }
};

and all the concrete humans can be added to list in

class Manage
{
private:
std::vector&lt;Human*&gt; humans;
std::vector&lt;HumanFactory*&gt; factories;
// register factory 
void registerFactory(HumanFactory* factory)
{
factories.push_back(factory);
}
void vInList()
{
int choice;
do
{
Menu(); // The menu has 6 choices
std::cin &gt;&gt; choice;
if (choice &gt;= 1 &amp;&amp; choice &lt;= factories.size())
{
Human* human = factories[choice - 1]-&gt;createHuman();
human-&gt;vInPrivate();
human-&gt;vIn();
humans.push_back(human);
}
else if (choice != 0)
{
std::cout &lt;&lt; &quot;Invalid choice!\n&quot;;
}
} while (choice != 0);
}
int main()
{
Manage manager;
manager.registerFactory(new StudentFactory());
// Register other factories as needed
manager.vInList();
manager.vOutList();
return 0;
}

I have provided code, not fully finished but I think will give you idea how to replace switch.

答案2

得分: 1

在这种情况下,我更喜欢定义一个使用您的类型作为键以及处理该类型所需的特定工作的函数(lambda或其他方式)的映射。伪代码如下:

std::map<int, std::function<void()>> type_map;

type_map[1] = [*this]() {                         
    List[iObject_num] = new Student;
    List[iObject_num]->vInPrivate(); // 输入基类的受保护信息
    List[iObject_num]->vIn(); // 输入每个子类的私有信息
    iObject_num++;
}

然后,对输入进行范围检查(它是否在映射中),如果是的话,执行该方法。

英文:

In situations like this I prefer to define a map that uses your type as the key and a function (lambda or otherwise) that handles the specific work needed for that type. To pseudocode it:

std::map&lt;int, funct&gt; type_map;
type_map[1] = [*this]() {                         
List[iObject_num]= new Student;
List[iObject_num]-&gt;vInPrivate(); // input the protected info of base class
List[iObject_num]-&gt;vIn();// input the private of each child class
iObject_num++;
}

Then range check your input (is it in the map), and if so, execute the method.

答案3

得分: 0

以下是翻译好的代码部分:

如果你只是想避免使用switch-case,你可以使用以下方法:

template <typename T, int x>
struct IndexedHumanType {
};

using AllIndexedHumanTypes = std::tuple<
  IndexedHumanType<Student, 1>,
  IndexedHumanType<Undergrad, 2>,
  IndexedHumanType<Worker, 3>,
  IndexedHumanType<Actor, 4>,
  IndexedHumanType<Musician, 5>
>;

class Manage {
private:
  template <typename T, int I, typename... Others>
  bool handle(int choice, std::tuple<IndexedHumanType<T, I>, Others...>&) {
    if (choice == I) {
      List[iObject_num] = new T;
      List[iObject_num]->vInPrivate();
      List[iObject_num]->vIn();
      ++iObject_num;
      return true;
    }
    if constexpr (sizeof...(Others) == 0) {
      return false;
    } else {
      return handle(choice, std::tuple<Others...>{});
    }
  }
  
  bool handle(int choice) {
    return handle(choice, AllIndexedHumanTypes{});
  }
...
};

这是静态多态性。如果你有多个地方需要使用switch-case序列,你可以将handle通用化,接受一个lambda函数,依次接受IndexedHumanType并执行必要的工作。

然而,从运行时效率的角度来看,最高效的解决方案仍然是使用switch-case。

英文:

If all you want is to avoid switch-case, you can use the following approach:

template &lt;typename T, int x&gt;
struct IndexedHumanType {
};
using AllIndexedHumanTypes = std::tuple&lt;
IndexedHumanType&lt;Student, 1&gt;,
IndexedHumanType&lt;Undergrad, 2&gt;,
IndexedHumanType&lt;Worker, 3&gt;,
IndexedHumanType&lt;Actor, 4&gt;,
IndexedHumanType&lt;Musician, 5&gt;
&gt;;
class Manage {
private:
template &lt;typename T, int I, typename... Others&gt;
bool handle(int choice, std::tuple&lt;IndexedHumanType&lt;T, I&gt;, Others...&gt;) {
if (choice == I) {
List[iObject_num] = new T;
List[iObject_num]-&gt;vInPrivate();
List[iObject_num]-&gt;vIn();
++iObject_num;
return true;
}
if constexpr (sizeof...(Others) == 0) {
return false;
} else {
return handle(choice, std::tuple&lt;Others...&gt;{});
}
}
bool handle(int choice) {
return handle(choice, AllIndexedHumanTypes{});
}
...
};

This is static polymorphism. If you have multiple places with switch-case sequences, you can generalize handle to accept a lambda function, accepting, in turn, IndexedHumanType, and performing whatever work is necessary.

However, the most efficient in terms of runtime solution is switch-case.

huangapple
  • 本文由 发表于 2023年6月13日 00:43:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76458701.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定