在.NET中使用C ++ / CLI实用程序:

时间:2013-03-09 13:23:18

标签: .net pointers c++-cli wrapper

我一直在开发一些DLL实用程序项目,以避免在其他项目中重复代码,以及我还没有尝试过的功能,算法和测试。其中一个项目是C ++ / CLI,这是我还在学习的语言,所以这个问题可能听起来很愚蠢。由于我在C ++ / CLI,F#和C#中有Library Projects,我使用C#控制台应用程序来测试它们。它不能与C ++ / CLI项目一起使用,因此我创建了一个C ++ / CLI控制台测试项目。它从未起作用,当我更改原始DLL C ++的名称时,引用未更新。当我(最终)发现问题时,我更改了.vcxproj文件,使得using指令成为可能,就像一个方法一样,但不是模板类Apont<typename T>,这是一种内部指针,但是与.NET类型System::IntPtr不同,使用T*类型的值而不是void*

我还发现(从本网站的帖子中)我必须在项目中使用我想在外面使用的内容,否则这些内容需要在元数据中发出。所以我在静态实用程序中有一个无用的静态方法用于此目的:

static void Funcionalidades()
{
    int i = 10;

    Apont<int> a2 = Apont<int>(i);            // stack
    Apont<int> ^a3 = gcnew Apont<int>(i);     // heap CLR

}

尽管如此,它不起作用。这是我在C ++ / CLI测试项目中的主要方法:

int main(array<System::String ^> ^args)
{
    int y(10);
    Apont<int> a = Apont<int>(y);

    Console::ReadKey();
    return 0;
}

以下是错误(我知道它可以用intellisense错误编译,但无论如何我都会显示它们):

error C2065: 'Apont' : undeclared identifier
error C2062: type 'int' unexpected
IntelliSense: identifier "Apont" is undefined
IntelliSense: type name is not allowed
IntelliSense: expected an expression

为什么这些错误在这里?我怎样才能纠正它们?

我很感激任何回答或回复。

编辑(澄清):

  • 这些错误不会发生在DLL项目中的Funcionalidades方法上,而是发生在测试项目中DLL之外的主方法上。
  • 我正在写头文件中的所有内容;我的意思是并非每个头文件都有一个相应的.cpp文件,尽管所有头文件都包含在至少一个.cpp文件中。
  • 有关Apont的更多信息:
    • Apont是一个模板(因为T *在内部使用,并且“不允许在通用类型的参数上进行间接”)。
    • Apont有一个复制构造函数,因此Apont<int> a = Apont<int>(someInt)应该可以工作;
    • Apont<int> a(someInt)不起作用;
    • Apont是某种内部指针;并且我没有发布整个代码,因为它不相关,我必须翻译varibles的名字,它可能有我可以轻易修复的错误,但这只会分散你的注意力。

NTH EDIT(其中'n'是我不知道的数字):

Apont你长期以来一直在抱怨的代码:

    template<typename T> public ref class Apont sealed : public IDisposable
    {
        bool eliminado;
        T *pointer;

        /*void Dispose(bool tudo)
        {
            if (!eliminado)
            {
                if (tudo)
                {
                    ~Apont();
                }
                else
                {
                    !Apont();
                }
            }
        }*/
        !Apont() // finalizador: limpa os recursos "unmanaged"
        {
            delete pointer;
            pointer = nullptr;
            eliminado = true;
        }

    public:
        Apont(T &valor)
        {
            pointer = &valor;
            eliminado = false;
            ErroSeNulo = false;
            ErroSeEliminado = true;
        }
        Apont(T &valor, bool erroSeEliminado, bool erroSeNulo)
        {
            pointer = &valor;
            eliminado = false;
            ErroSeEliminado = erroSeEliminado;
            ErroSeNulo = erroSeNulo;
        }
        Apont(Apont<T> %outroApont)
        {
            this->pointer = &outroApont
        }

        property bool ErroSeEliminado;
        property bool ErroSeNulo;
        property T Valor
        {
            T get()
            {
                if (pointer != nullptr)             
                    return *pointer;
                else if (eliminado && ErroSeEliminado)
                    throw gcnew ObjectDisposedException("O objeto já foi pelo menos parcialmente eliminadao.");
                else if (ErroSeNulo)
                    throw gcnew NullReferenceException();
                else
                    return 0;
            }
        }

        /*
        Apont operator ~(/*T valor* /)
        {
            // este operador tem de ser declarado fora desta classe 
        }*/
        T operator !(/*Apont apont*/)
        {
            return Valor;
        }
        void operator =(Apont<T> outroApont)
        {
            pointer = outroApont;
            ErroSeEliminado = outroApont.ErroSeEliminado;
            ErroSeNulo = outroApont.ErroSeNulo;             
        }
        template<typename U> void operator =(Apont<U> outroApont)
        {
            pointer = safe_cast<T>(outroApont.pointer);
            ErroSeEliminado = safe_cast<T>(outroApont.ErroSeEliminado);
            ErroSeNulo = safe_cast<T>(outroApont.ErroSeNulo);
        }
        /*
        void operator =(T *&outroPointer)
        {
            pointer = outroPointer;
        }
        template<typename U> void operator =(U *&outroPointer)
        {
            pointer = safe_cast<T>(outroPointer);
        }*/
        void operator =(T *outroPointer)
        {
            pointer = outroPointer;
        }
        template<typename U> void operator =(U *outroPointer)
        {
            pointer = safe_cast<T>(outroPointer);
        }


        ~Apont() // destruidor: limpa todos os recursos
        {               
            this->!Apont();
        }

        // Error C2605: 'Dispose': this method is reserved within a managed class
        // O código será gerado automaticamente a partir do finalizador e do destrutor
    };

    template<typename T> Apont<T> operator ~(T &valor)
    {
        return gcnew Apont<T>(valor);
    }

5 个答案:

答案 0 :(得分:3)

出现的错误通常是缺少类的声明。这通常会发生,然后标题中的代码被标题保护。

这是怎么发生的?

如果你在Funcionalidades中包含Apont标题然后在Apont中包含Funcionalidades标题而不是你遇到麻烦。发生这种情况是因为如果你在包括Funcionalidades之前在你的主要包括Apont,Funcionalidades标题缺少Apont的声明。

然后你第一次包括Apont,它将启用头部保护。然后它将包括Funcionalidades,其中包括Apont。因为标头防护已经启用,Funcionalidades标头将不会有Apont声明。与此同时Apont声明甚至还没有在Apont的相应头文件中开始。而且你在这里,因为这个问题在main中无法编译,因为在库编译时你没有这样的依赖。

如何解决?

在Cpp代码中移动Apont在Funcionalidades实现中的使用,保持头文件没有依赖。

答案 1 :(得分:1)

它只是抱怨它不知道“Apont”。我不知道它是什么,你没有发布它的代码。只是声明它的任意版本:

generic<typename T>
public ref class Apont {
    T value;
public:
    Apont(T init) : value(init) {}
};

static void Funcionalidades()
{
    int i = 10;

    Apont<int> a2(i);                      // stack
    Apont<int> ^a3 = gcnew Apont<int>(i);  // heap CLR

}

请注意“a2”的更改代码,避免引用类型的复制构造函数。再次在主要:

    Apont<int> a(y);

答案 2 :(得分:1)

我必须在项目内部使用我想在

之外使用的内容

如果是这样,你有没有在任何地方调用静态函数?机会是未被调用的功能可能会被优化。

答案 3 :(得分:1)

使用名称空间语句会丢失吗?确保在main方法中使用正确的using语句。还要确保添加了一个引用,以便包含main方法的项目引用包含Apont的项目。

答案 4 :(得分:1)

很抱歉花了这么长时间才回复你:我有几点需要帮助解决问题。   - 模板类声明为sealed:这意味着你不能将它用作基类(与模板化类的主要原因相反)。至少它不需要,所以它可能值得删除。   - 其次,更重要的是,在编译时评估C ++模板,因此,由于没有声明指定的实例,因此没有对Apont进行评估,也没有将其编译到DLL中。要启用模板类的特定版本,您可以在UtilCMM.h文件的末尾添加以下内容:

  • class template Apont<int>;
  • class template Apont<float>;
  • class template Apont<double>;

这是因为在编译时由预处理器扩展C ++模板,就像宏一样,但是只有在编译时才会处理显式使用的版本:这是一个很大的优点和缺点。我一直找到的解决方案(与其他C ++程序员达成共识)是:

  • 明确实例化您需要在dll中导出的版本
  • 提供一个带有模板的头文件,然后可以由谁来使用 - 无论您是将代码分发到

如果有其他方法可以实现相同目标,我还没有遇到过它们,并且很想知道,唉这些是模板的局限性。

然后在编译时你应该有三个特定的版本。只需为要包含在DLL中的每种类型添加更多内容。对不起我之前没有发现它,当我看到完整代码时它们都跳出来了。现在如果我可以让项目编译我可以自己尝试更改(我的VS版本不加载你的vcproj文件版本,典型值)。