接口动态数组 [英] dynamic array of interfaces

查看:92
本文介绍了接口动态数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


我有一个实现接口MyInterface的MyClass类:

Hi,
I have a class MyClass which implements an interface MyInterface:

class MyInterface {
public:
   virtual void myFunction () = 0;
};

class MyClass : public MyInterface {
public:
    MyClass ();
    virtual ~MyClass ();
    void myFunction ();
};


现在,我想制作一个MyClass对象的动态数组.
我的第一次尝试是:


Now I want to make a dynamic array of MyClass objects.
My first attempt was:

MyInterface *a;
a = new MyClass[n];
for (int i=0; i<n; i++) {
    a[i].myFunction ();
}


在运行时由于n>而失败1.

因此,我想出了一个可能的解决方案,如下所示:
(A)


which failed at runtime for n > 1.

So I come to a possible solution like this:
(A)

MyInterface **a;
a = new MyInterface*[n];
for (int i=0; i<n; i++) {
    a[i] = new MyClass ();
    a[i] ->myFunction ();
}


此解决方案的问题在于,当我想通过以下方式回收使用的资源时:


The problem with this solution is that when I want to reclaim the used resources with:

for (int i=0; i<n; i++) {
    delete a[i];
}
delete []a;

与以下内容相比确实需要很长时间:
(B)

it really takes a long time, if compared to:
(B)

MyClass *a;
a = new MyClass[n];
for (int i=0; i<n; i++) {
    a[i].myFunction();
}
delete []a;



我注意到用(A)分配比(B)占用更多的内存,有人可以解释吗?

谢谢.



I notice that allocating with (A) takes a lot more memory than (B), anyone can explain this?

Thanks.

推荐答案

如果您正在使用多态,则必须使用指针或引用,就无法实现带有值的多态.
在这种情况下:
If you are using polymorphism then you have to use a pointer or reference, you can not achieve polymorphism with values.
In this case:
MyInterface *a;
a = new MyClass[n];
for (int i=0; i<n; i++) {
    a[i].myFunction ();
}


您的MyInterface *a数组"将类实例本身存储为值.您的赋值a = new MyClass[n];只是因为您展示了C的相对危险的特性而进行编译(编译-不起作用),也就是说,在大多数情况下(少数情况除外),类型T的数组标识符和类型T的指针可以互换并自动转换带有模板和功能参数).

不过,解决方案A和B都是正确的. A案例需要更多的内存,因为您分配了很多小块而不是一个大块,并且如果您定期释放/分配块,可能会导致内存碎片,但是在这种情况下,多余的空间可能来自分配器的内存使用情况每个分配的块使用一些额外的内存来跟踪堆中已分配/可用的空间.

但是,如果您需要提供MyInterface **a,则可以将解决方案A和B混合使用,作为一种优化,您既可以在解决方案A中分配MyInterface **a,又可以在解决方案B中分配MyClass *b,然后再填写指向b数组项的接口指针.

忘记提及的东西更像是对您的问题的答案:


Your MyInterface *a "array" stores the the class instances themselves as values. Your assignment a = new MyClass[n]; compiles (compiles - not works) just because you explited a relatively dangerous trait of C, that is array identifiers of type T and pointers to type T are exchangeable and auto-casted in most situations (except for a few cases with templates and function parameters).

Both solution A and B are correct though. Your A case takes much more memory because you allocated a lot of small chunks instead of one big chunk and that can lead to memory fragmentation if you regularly free/allocate chunks but in your case the extra wasted space probably comes from memory usage of your allocator that uses some extra memory per allocated block to keep track of allocated/free space in your heap.

However if you need to provide MyInterface **a then you can mix solution A and B as an optimization, you allocate both a MyInterface **a like in solution A and a MyClass *b like in solution B and then later you can fill in the a interface pointers to point to the items of the b array.

Forgot to mention something that is much more like an answer to your problem:

class Base
{
public:
    Base(int base_data=0)
        : m_BaseData(base_data)
    {
    }
private:
    int m_BaseData;
};

class Derived : public Base
{
public:
    Derived(int derived_data=0)
        : m_DerivedData(derived_data)
    {
    }
private:
    int m_DerivedData;
};

void test()
{
    // EXAMPLE #1
    const int ARRAY_SIZE = 5;
    Base* base_array = new Base[ARRAY_SIZE];
    Derived* derived_array = new Derived[ARRAY_SIZE];
    printf("base_array member_size: %d\n", (int)((char*)&base_array[1]-(char*)&base_array[0]));
    // note: base_array member_size is 4 on my machine
    printf("derived_array member_size: %d\n", (int)((char*)&derived_array[1]-(char*)&derived_array[0]));
    // note derived_array member_size is 8 on my machine

    base_array = new Derived[ARRAY_SIZE];
    // note that the first (index 0) member pointed by base_array will be accessed perfectly
    // because the assignment performed a static cast (!!!) and adjusted the pointer (by offsetting
    // it if needed). However if you perform an indexing on a (Base*) type then you will be
    // accessing a memory area that is 4 bytes (base_array member_size) past the current value
    // of the pointer and this gives a wrong result since you allocated a Derived array whose
    // members are 8 bytes large. For this simple reason you MUST always assign a dynamically
    // allocated C++ array to exactly same type of pointer as the type of the members in the array!!!

    // EXAMPLE #2
    Derived derived;
    // This is another common mistake related to inheritance and storing instances by value:
    // Copying only the base of a larger object that is an instance of a class derived from the base class.
    // This is perfectly valid in many cases but sometimes it causes a bug, sometimes you store
    // data in the base part of the derived class that is not valid without the derived parts of
    // the object. To disable copying just the base part of an instance put the base class copy
    // constructor to protected.
    Base base(derived);
    // OR
    Base base2 = derived;
}


使用std :: vector的解决方案...

在某处声明
Solution using std::vector...

Declare this somewhere
std::vector<myinterface *> InterfaceList;



要添加接口...



To add an interface...

MyInterface *pNewInterface;
pNewInterface = new MyClass;
if (pNewInterface)
   InterfaceList.push_back(pNewInterface);



遍历接口



To iterate through the interfaces

size_t n = InterfaceList.size();
for (size_t i=0; i < n; i++) {
    InterfaceList[i]->myFunction();
}



然后稍后将其删除...



Then to delete them later...

size_t n = InterfaceList.size();
for (size_t i=0; i < n; i++) {
    delete InterfaceList[i];
}
InterfaceList.clear();


这篇关于接口动态数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆