Mixed types are not supported

2019-05-22 20:35发布

问题:

Please have a look at the following header file

#pragma once
using namespace UsbLibrary;

ref class MissileLauncher
{
public:
    MissileLauncher(void);

private:
    //Bytes used in command
    unsigned char UP[10];
    unsigned char RIGHT[10];
    unsigned char LEFT[10];
    unsigned char DOWN[10];

    unsigned char FIRE[10];
    unsigned char STOP[10];
    unsigned char LED_OFF[9];
    unsigned char LED_ON[9];

    UsbHidPort USB;
};

I am using a Visual C++ project (C++/CLI ?) in visual studio professional 2010. When I run this code, I get lot of errors

Error   1   error C4368: cannot define 'UP' as a member of managed 'MissileLauncher': mixed types are not supported 
Error   2   error C4368: cannot define 'RIGHT' as a member of managed 'MissileLauncher': mixed types are not supported  
Error   3   error C4368: cannot define 'LEFT' as a member of managed 'MissileLauncher': mixed types are not supported   
Error   4   error C4368: cannot define 'DOWN' as a member of managed 'MissileLauncher': mixed types are not supported   
Error   5   error C4368: cannot define 'FIRE' as a member of managed 'MissileLauncher': mixed types are not supported   
Error   6   error C4368: cannot define 'STOP' as a member of managed 'MissileLauncher': mixed types are not supported   
Error   7   error C4368: cannot define 'LED_OFF' as a member of managed 'MissileLauncher': mixed types are not supported    
Error   8   error C4368: cannot define 'LED_ON' as a member of managed 'MissileLauncher': mixed types are not supported 

Here, the namespace USBLibrary is coming from a C# dll file. The UsbHidPort; is an object from that C# dll

So, why am I getting this error? Any ideas?

回答1:

It isn't actually a problem in this specific case, at least from what's visible, but the C++/CLI compiler tries to prevent you from shooting your leg off, missile style. The garbage collector moves objects when it compacts the heap. Which makes native objects very dangerous, any pointers to them will become invalid and will destroy the GC heap when you write through them. The collector is powerless to update those pointers, it cannot find them. The risk is too high so the compiler just forbids it.

An alternative is to declare these members as pointers instead and allocate the array with operator new in the class constructor.

private:
    unsigned char* UP;
    // etc..
public:
    MissileLauncher() {
        UP = new unsigned char[10];
        // etc..
    }
    ~MissileLauncher() {
        this->!MissileLauncher();
        UP = nullptr;   // Destructor may be called more than once 
    }
    !MissileLauncher() {
        delete[] UP;
        // etc...
    }

Note the requirement for a destructor and a finalizer to release the memory for these arrays. Defining a destructor also brings along the burden of the client programmer having to call it (Dispose() or using in a C# client program, delete or stack semantics in a C++/CLI program), skipping it for such a small allocation is not unreasonable. And last but not least, consider the sane solution and use a managed array:

private:
    array<Byte>^ UP;
    // etc..
public:
    MissileLauncher() {
        UP = gcnew array<Byte>(10);
        // etc..
    }


回答2:

The problem is you're mixing managed and unmanaged types which is what the compiler warning means. The class is a managed class but the integer arrays count as unmanaged objects. This causes problems with garbage collection. Read all about it here:

http://blogs.msdn.com/b/branbray/archive/2005/07/20/441099.aspx

Why not use managed arrays?