【问题标题】:Call different classes in different time in same function在同一函数中在不同时间调用不同的类
【发布时间】:2010-11-06 18:18:31
【问题描述】:

我只是无法想象一种方法来调用具有通用性的函数。我有一个代码,它必须在不同的时刻在两个不同的类中调用一个函数。

我有 A 类和 B 类,我可以访问一次或其他时间。或者我访问 A 或访问 B。不是两者都属于同一类型。

我有这个程序的代码,但我无法想象如何做到这一点。或者如果这对性能或编码有好处。我只是想消除C类但我不知道如何。

有什么想法吗?

我的班级 { 民众: MyClass() {} //constructor padrão, não deve ser utilizado isoladamente 虚拟整数 a() = 0; 虚拟 int b() = 0; 诠释 c() { 返回 b(); } }; A类:公共MyClass { 民众: int a() { 返回 1; } int b() { 返回 1; } int d() { 返回 1; } }; B类:公共MyClass { 民众: int a() { 返回 1; } int b() { 返回 1; } int e() { 返回 1; } }; C类 { 民众: 约; B CB; 枚举 TIPO { A, B }; 蒂波蒂波; C(TIPO Tipo) { Tipo = Tipo; } 诠释一个() { 开关(提示) { 案例一: 返回 ca.a(); 休息; 案例B: 返回 cb.b(); 休息; 默认: 休息; } } }; 无效的主要() { C c(C::B); c.a(); 返回; }

【问题讨论】:

  • 不太确定你在问什么,但你可能想检查多线程

标签: c++ class


【解决方案1】:

如果我理解正确,您是在尝试消除成员 (ca,cb),然后调用适当的基类方法。

如果是这种情况,可以使用:

switch(Tipo) {
case A:
    return A::a();
case B:
    return B::a();
}

但是,我建议重新审视您的设计。通常,此类情况通常可以通过重新思考/重新设计类设计来处理,以便有一个定义 a() 的基类或接口,而不是创建一个具有 2 个基类的具体类,而是创建两个特定的类之一,从单个基类派生的具体类。这里不需要多重继承。 (尤其如此,因为您在构建时就知道类型。)

【讨论】:

  • 两个冒号! A::a() 和 B::a()
【解决方案2】:

由于您已经编写了“A”和“B”,因此您实际上并不需要 C 类。通过将您的成员函数声明为“虚拟”,您正在使用运行时多态性,这将导致调用“正确”的函数:

void foo (MyClass & mc) {
  mc.a ();
}

int main () {
  A a;
  B b;

  foo (a);  // 'mc.a()' will call 'A::a'
  foo (b);  // 'mc.a()' will call 'B::a'
}

还有其他需要从 C 继承的原因吗?

【讨论】:

    【解决方案3】:

    首先,确定你的 A 和 B 类是通过继承还是通过组合属于 C。现在你正在做这两个,这既使你的代码膨胀,又使它变得混乱。

    如果您确实选择继承,那么您还有另一个问题:类似命名的重写方法,如果您没有听说过,Deadly Diamond of Death. 多重继承的主要原因是邪恶的。避免它,除非没有其他方法可以完成工作。

    如果您使用组合(我的建议),那么在我看来,您对“不同时”的规范变得不必要了。您没有访问相同的数据,因此不可能出现竞争条件。而且,如果您(出于某种邪恶的原因)决定访问相同的内存空间,那么您将需要复习多线程,其实现会因您开发的每个平台而异。

    【讨论】:

    • 我还听说它被称为“脆弱基类”问题。但在这种情况下,这是一个问题,因为两个继承的类共享同一个父类,并覆盖方法 a() 和 b()。有经验的程序员会避免这两种错误。
    • 我是一位经验丰富的程序员,我看不出有什么问题。它是什么。如果您尝试使用 a() 或 b(),编译器会告诉您存在歧义。在继续之前,您必须解决歧义。没问题。一个有经验的程序员不会仅仅在这个问题上避免多重继承(我也不提倡它),但你需要在这里仔细挑选你的话.....
    • 好吧,OP 在这里提出了一点:C 类不再继承自 A 和 B。我明白你的意思,但是在 Stepanov 和 Lee 的原始 STL 实现之外,我很少看到多重继承解决了一个无法以更简洁的方式解决的问题,无论是通过委托还是抽象接口。如果我要使用多重继承,我会用它来混合不同的函数集,而不是像 OP 那样将已经密切相关的类混在一起。这就是导致我将原始代码称为错误而不是耸耸肩的歧义的原因。
    【解决方案4】:

    好的,我猜你希望 C::a() 根据 C 的“类型”或“模式”调用 A::a() 或 B::b()。首先没有必要让C继承A和B。

    class C
    {
      private:
        A ca;  
        B cb; 
    
        enum TIPO { A, B };  
        TIPO Tipo;
    
      public:
        SetTipo(TIPO tipo) { Tipo = tipo; }
    
        // ..
    };
    
    void main()  
    {  
        C c(C::B);  // Start with mode B and call B::b()
        c.a();
        c.SetTipo(C::A); // Now I'm in mode A .. call A::a()
        c.a();   
        return;  
    }  
    

    这假定 C 确实应该拥有一个 A 实例和一个 B 实例,我不确定这是否是您想要的。你的问题没有说明是不是这样。

    干杯

    【讨论】:

      【解决方案5】:

      这个问题很不清楚。我对这个问题有另一种解释,以及一个答案。

      解释:给定:

       class C {
       public:
        int a();
        int b();
       };
      

      您想调用方法 a() 或方法 b(),可在运行时选择。解决方案:成员函数指针。

      成员函数指针类似于常规 C 函数指针,不同之处在于它适用于类中的方法,并且其类型签名包括调用它的类的名称。以下是如何在我刚刚给出的课程中使用一个:

        typedef int (C::*SELECT_FUNC)(void);
      

      这是成员函数指针的声明。它类似于常规 C 函数指针的声明,只是添加了一个类名。现在我们可以分配它了:

       SELECT_FUNC ptr = &C::a;
       SELECT_FUNC other_ptr = &C::b;
      

      然后调用:

       C item;
       C *item_ptr;
      
       int rv = item.*ptr();
       int rv2 = item_ptr->*other_ptr;
      

      这种语法很时髦。将“*”视为“取消引用”。我们正在取消引用成员函数指针以获取 METHOD,此时我们可以以正常方式调用该方法。

      这很酷的一点是:方法是否是虚拟的甚至都没有关系。您可以将虚拟方法或非虚拟方法分配给成员函数指针。如果您通过函数指针调用方法并且该方法恰好是虚拟的,那么您将获得真正的虚拟调用(即,如果函数指针被声明为指向基类方法,但您使用派生类实例"this",那么派生类方法就会被调用,就像普通的虚调用一样。)

      我会仔细考虑您的要求。您的问题问得不好,这使我相信您不了解自己真正想要实现的目标。一旦您了解了您想要实现的目标,那么类层次结构或成员函数指针(或两者)可能是解决您的问题的最佳选择。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多