【问题标题】:Pointer to a Class Type指向类类型的指针
【发布时间】:2015-04-06 11:12:22
【问题描述】:

基本上,我正在尝试解决无法将派生类型作为派生类型存储在基类型的(值)数组中的问题。我有多个类存储一到三个整数,但必须具有非常不同的函数集。我会使用一个指针数组,但是整个数组会向前遍历,然后不断向后遍历,主要是线性的,因此最好将它们全部放在内存中。我可以创建多个数组,每个类型一个,然后一个指向每个类型的指针数组,但这会很快变得非常笨拙,并且实际上与每个元素整齐地包装在它前面的元素和一个过程之间的元素不同它按运行时的访问顺序。

所以我在想的是,我用三个整数和一个指针创建一个 POD 结构,并用它们填充一个数组,然后使用该指针访问多态函数。它最终会是这样的:(请原谅这里糟糕的编码,我只是想传达这个概念)

class A { 
    int aa( &foo f ) { return 1; }   
    int dd() { return 9; } 
};
class B : A {
    int aa( &foo f ) { return f.b; } 
};
class C : A {
    int aa( &foo f ) { return cc() + f.c - f.a; }
    int cc() { return 4; }
};
class D : B {
    int dd() { return 7; } 
};
struct foo{ int a, b, c; A* ptr; };

const A AA = A(); const B BB = B(); const C CC = C(); const D DD = D();
foo[100] foos;

init() {
    foo[0] = foo{ 1, 2, 3, &BB };
    // etc fill foos with various foo elements
}
bar(){
    for ( int i = 0; i < 100; ++i ){
        print foos[i].ptr.aa( &foos[i] );
        print foos[i].ptr.dd();
    }
}
main(){ 
     init(); 
     while(true)
         bar(); 
}

我只是想知道这是否是实现我想要实现的目标的最佳方式,或者是否有更好的解决方案?理想情况下,我只指向一个类而不是类的实例,但我认为我不能真正做到这一点... 理想情况下我会将它们作为多个派生类型存储在一个数组中但由于显而易见的原因,它不会飞。

【问题讨论】:

  • 有什么理由不能只使用有区别的联合,比如 Boost.Variant?
  • 除了从来没有遇到过?我不知道。在每个函数中没有一堆笨拙的 switch 语句的情况下,如何在保留相同类型的同时创建一个多态?
  • 好的,只是检查您是否了解它们并排除了它们。他们应该做你需要的事情,用访问而不是 switch 语句。

标签: c++ arrays function class pointers


【解决方案1】:

...我正在尝试解决无法将派生类型作为派生类型存储在基类型的(值)数组中的问题。

可以将派生类型作为值存储在数组中 - 您只是不能将它们存储为基本类型的实例。

union 的具体叶子类型几乎是您想要的,但无法确定联合的哪个成员是活动的,或者使用多态调度。

有区别的联合是告诉你哪个成员是活的,但不直接帮助调度的联合。

Boost.Variant 是一个特定的可区分联合,它为多态分派提供了一种干净的机制 - 不使用 virtual,而是为每个具体存储类型使用具有重载的访问者。在这种情况下,您甚至不需要将存储类型与公共抽象基相关联——它们可以完全不相关。在tutorial 中查找apply_visitor 了解详情。

【讨论】:

    【解决方案2】:

    你需要多态性。在您的示例中,所有类都有标准方法。您需要使它们成为虚拟的,以便可以应用多态性。

    class A { 
        virtual int aa( foo& f )const { return 1; }   
        virtual int dd()const { return 9; } 
    };
    class B : A {
        virtual int aa( foo& f )const { return f.b; } 
    };
    class C : A {
        virtual int aa( foo& f )const { return cc() + f.c - f.a; }
        int cc()const { return 4; }// this doesn't need to be virtual because is not in the base class A
    };
    class D : B {
        virtual int dd()const { return 7; } 
    };
    

    以下是有关此主题的一些信息:http://www.cplusplus.com/doc/tutorial/polymorphism/。还有一些关于如何使用指针的信息。 我建议查看智能指针:http://www.cplusplus.com/reference/memory/shared_ptr/?kw=shared_ptr 您应该查看的另一个主题是 constness:搜索“constness c++”(不能发布超过 2 个链接)

    struct foo{ int a, b, c;const A* ptr; }; // const A* instead of A*
    

    【讨论】:

    【解决方案3】:

    您正在寻找的是虚函数。

    在下面的例子中:

      class A
      {
    
           virtual void foo(){printf("A is called");};
      }
      class B : public A
      {
             void foo(){printf("B is called");};
      }
    
      ...
      A* ptr = new B();
      ptr->foo();
    

    会产生“B被称为”。

    如果你不想使用虚函数(例如为了节省内存),你可以使用动态强制转换,但这会导致显着的性能损失。

    请注意,您需要至少 1 个虚拟函数才能执行动态转换。

    在下面的例子中:

        class A {...}
        class B : public A {...}
        class C : public A {...}
    
        A* ptr1 = new C();
        B* ptr2 = dynamic_cast<B*>(ptr1);
        C* ptr3 = dynamic_cast<C*>(ptr1);
    

    ptr2 将为空,而 ptr3 将有一个值。 所以你可以做出以下(非常错误的)构造:

         if (ptr2)
         {
            ptr2->bb();
         } else if (ptr3)
         {
            ptr3->cc();
         }
    

    最后,您可以通过拥有自己的类型机制来摆脱动态转换,然后只需将 C 转换为正确的类。

    【讨论】:

    • 虚函数对内存有什么影响?如果我只初始化了每个类的一个实例,并且有几个指向每个类的指针会产生与每个类的多个实例相同的影响(假设函数以相同的速率访问)?
    • 我真的不想显式地转换任何东西,或者如果我可以避免它,我必须手动找出类型,因为我想尽快在数组中移动......
    • 然后在对象内部使用虚函数或仿函数数组,你应该会很好。
    猜你喜欢
    • 2011-09-14
    • 2010-10-22
    • 1970-01-01
    • 1970-01-01
    • 2012-05-12
    • 1970-01-01
    • 2019-08-28
    • 2011-12-29
    • 1970-01-01
    相关资源
    最近更新 更多