English 中文(简体)
如何创建一系列类类型?
原标题:How to create an array of classes types?

我有一个单级的“Base ”, 和几个从Base 衍生出来的数十个类。我想有一个方法,用一个索引来给我创造正确的类。像这样:

class Base
{
};

class A : public Base
{
}

class B : public Base
{
}

class C : public Base
{
}

Type array = { A, B, C };

然后我就可以做 new 数组[i];

如何用 C++( 0x) 实现这一点? 通常我会使用“ 抽象工厂模式 ” 。 但是, 由于我拥有大量衍生类别, 这将真正减缓程序。

因为派生的班级 只有在我学会使用这个课后 才会使用这个课:

Base *array = { new A, new B, new C };

但这会导致大量的记忆消耗, 不算不是每个班级都会被使用。

有什么建议吗?

最佳回答

您不能使用一系列类,但您可以对函数使用一系列指针。

typedef std::unique_ptr<Base> (*Creator)();

template <typename T>
std::unique_ptr<Base> make() { return new T{}; }

Creator const array[] = { make<A>, make<B>, make<C> };

int main() {
    std::unique_ptr<Base> b = array[1]();

    b->foo();
}

对于担心创建这么多模板功能的成本的人来说,这里举一个例子:

#include <stdio.h>

struct Base { virtual void foo() const = 0; };

struct A: Base { void foo() const { printf("A"); } };
struct B: Base { void foo() const { printf("B"); } };
struct C: Base { void foo() const { printf("C"); } };


typedef Base* (*Creator)();

template <typename T>
static Base* make() { return new T{}; }

static Creator const array[] = { make<A>, make<B>, make<C> };

Base* select_array(int i) {
    return array[i]();
}

Base* select_switch(int i) {
    switch(i) {
    case 0: return make<A>();
    case 1: return make<B>();
    case 2: return make<C>();
    default: return 0;
    }
}

LLVM/Clang产生以下产出:

define %struct.Base* @select_array(int)(i32 %i) uwtable {
  %1 = sext i32 %i to i64
  %2 = getelementptr inbounds [3 x %struct.Base* ()*]* @array, i64 0, i64 %1
  %3 = load %struct.Base* ()** %2, align 8, !tbaa !0
  %4 = tail call %struct.Base* %3()
  ret %struct.Base* %4
}

define noalias %struct.Base* @select_switch(int)(i32 %i) uwtable {
  switch i32 %i, label %13 [
    i32 0, label %1
    i32 1, label %5
    i32 2, label %9
  ]

; <label>:1                                       ; preds = %0
  %2 = tail call noalias i8* @operator new(unsigned long)(i64 8)
  %3 = bitcast i8* %2 to i32 (...)***
  store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @vtable for A, i64 0, i64 2) to i32 (...)**), i32 (...)*** %3, align 8
  %4 = bitcast i8* %2 to %struct.Base*
  br label %13

; <label>:5                                       ; preds = %0
  %6 = tail call noalias i8* @operator new(unsigned long)(i64 8)
  %7 = bitcast i8* %6 to i32 (...)***
  store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @vtable for B, i64 0, i64 2) to i32 (...)**), i32 (...)*** %7, align 8
  %8 = bitcast i8* %6 to %struct.Base*
  br label %13

; <label>:9                                       ; preds = %0
  %10 = tail call noalias i8* @operator new(unsigned long)(i64 8)
  %11 = bitcast i8* %10 to i32 (...)***
  store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @vtable for C, i64 0, i64 2) to i32 (...)**), i32 (...)*** %11, align 8
  %12 = bitcast i8* %10 to %struct.Base*
  br label %13

; <label>:13                                      ; preds = %9, %5, %1, %0
  %.0 = phi %struct.Base* [ %12, %9 ], [ %8, %5 ], [ %4, %1 ], [ null, %0 ]
  ret %struct.Base* %.0
}

不幸的是,用常规数组代码自动嵌入函数不够智能( LLVM 优化器的已知问题, 我不知道 gcc 是否做得更好)... 但使用 < code> switch 确实有可能。

问题回答
typedef Base* BaseMaker();

template <class X> Base* make() {
  return new X;
}

BaseMaker* makers[] = { make<A>, make<B>, make<C> };

Base* b = makers[2]();




相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?

热门标签