2015-02-06 127 views
0

本质上,我试图解决无法将派生类型作为派生类型存储在基类型的(值)数组中的问题。我有多个存储一到三个整数的类,但必须有非常不同的函数集。我会使用一个指针数组,但是整个数组是向前遍历的,然后不断地向后遍历,主要是线性的,所以把它们全部放在内存中是比较好的。我可以创建多个数组,每个类型都有一个数组,然后是指向每个数组的指针数组,但是这样做会非常笨拙,实际上不会像每个元素在前一个元素和后一个元素之间整齐排列一样它按运行时访问的顺序排列。指向类类型的指针

所以我在想的是,我用三个整数和一个指针做一个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(); 
} 

我只是想知道这是否是去了解我想要的东西的最佳方式实现还是有更好的解决方案?理想情况下,我只是指向一个类而不是一个类的实例,但我不认为我真的可以这样做...... 理想情况下我会将它们作为多个派生类型存储在数组中,但出于显而易见的原因不会飞。

+0

是否有一个原因,你不能只使用歧视联盟,如Boost.Variant? – Useless 2015-02-06 10:35:38

+0

除了从来没有遇到过他们?我不确定。我如何在保持相同类型的同时在每个函数中没有一堆笨拙的开关语句的情况下制作一个多态的? – User6897 2015-02-06 13:12:17

+0

好吧,只是检查你是否知道他们,并排除他们。他们应该做你所需要的事情,用访问而不是转换语句。 – Useless 2015-02-06 16:53:08

回答

0

你在找什么是虚拟功能。

在波纹管例如:

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强制转换为正确的类: 所以,你可以做如下(非常错误的)结构。

+0

虚拟功能对内存有什么影响?如果每个类只有一个实例被初始化,并且指向每个类的几个指针会具有相同的影响,如果我有每个类的几个实例(前提是函数以相同的速率访问)? – User6897 2015-02-06 13:29:48

+0

我真的不想明确地施放任何东西,或者必须手动计算出类型,如果我可以避免它,因为我想尽可能快地移动数组... – User6897 2015-02-06 13:44:19

+0

然后在对象内部使用虚函数或函子阵列你应该很好。 – MichaelCMS 2015-02-06 14:02:46

0

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

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 另一个问题你应该看看是常量性:搜索“不变性C++”(不能发布超过2个链接)

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

感谢您的链接! 这是否声明一个const指针指向A或一个指向const A的指针? – User6897 2015-02-06 13:56:23

+0

在这里你可以得到一些信息:http://www.codeguru.com/cpp/cpp/cpp_mfc/general/article.php/c6967/Constant-Pointers-and-Pointers-to-Constants.htm 这是一个指向常量A的指针 – Milan 2015-02-06 16:20:10

0

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

可以店派生类型,作为值,在数组中 - 你无法将它们存储为基础类型的实例。

A union你的混凝土叶片类型几乎是你想要的,但没有办法找出哪个工会的成员是生活的,或者使用多态派遣。

A 歧视联盟是告诉你哪个成员是生活的,但不直接帮助调度。

Boost.Variant是一个特定的识别联合提供了一个干净的机制,多态分派 - 不使用virtual,但使用与重载每个具体存储类型的访问者。在这种情况下,你甚至不需要存储的类型与一个通用的抽象基础相关 - 它们可以完全不相关。有关详细信息,请在tutorial中查找apply_visitor