C# 创建c++;没有静态方法的动态链接库 我在C++中创建了一个DLL。以下是一个例子: namespace MathFuncs { class MyMathFuncs { public: // Returns a + b static __declspec(dllexport) double Add(double a, double b); // Returns a - b static __declspec(dllexport) double Subtract(double a, double b); // Returns a * b static __declspec(dllexport) double Multiply(double a, double b); // Returns a / b // Throws DivideByZeroException if b is 0 static __declspec(dllexport) double Divide(double a, double b); }; }

C# 创建c++;没有静态方法的动态链接库 我在C++中创建了一个DLL。以下是一个例子: namespace MathFuncs { class MyMathFuncs { public: // Returns a + b static __declspec(dllexport) double Add(double a, double b); // Returns a - b static __declspec(dllexport) double Subtract(double a, double b); // Returns a * b static __declspec(dllexport) double Multiply(double a, double b); // Returns a / b // Throws DivideByZeroException if b is 0 static __declspec(dllexport) double Divide(double a, double b); }; },c#,c++,ios,dll,C#,C++,Ios,Dll,所有方法都是静态的,静态方法有很多限制,所以我的问题是,如果没有静态方法,如何实现相同的方法?我是否总是需要在DLL中使用静态方法?我想在C#和IOS应用程序中导入此DLL。您必须使用全局的C风格方法。原因是 基本上可以归结为:C函数可以很好地转换为DLL导出,因为C在语言特性方面“更贴近实际”。C更直接地翻译成机器代码。C++在编译器级别上做了很多工作,给了你很多不能在C++环境之外使用的特性。因此,导出的函数应该遵循C样式,以便跨DLL边界正常运行。这意味着没有模板,没有内联代码,没有非PO

所有方法都是静态的,静态方法有很多限制,所以我的问题是,如果没有静态方法,如何实现相同的方法?我是否总是需要在DLL中使用静态方法?我想在C#和IOS应用程序中导入此DLL。

您必须使用全局的C风格方法。原因是

基本上可以归结为:C函数可以很好地转换为DLL导出,因为C在语言特性方面“更贴近实际”。C更直接地翻译成机器代码。C++在编译器级别上做了很多工作,给了你很多不能在C++环境之外使用的特性。因此,导出的函数应该遵循C样式,以便跨DLL边界正常运行。这意味着没有模板,没有内联代码,没有非POD类或结构

考虑以下代码:

extern "C"
{
    __declspec(dllexport) int GlobalFunc(int n)
    {
        return n;
    }

    namespace SomeNamespace
    {
        __declspec(dllexport) int NamespaceFunction(int n)
        {
            return n;
        }
    }

    class MyClass
    {
        __declspec(dllexport) int ClassNonStatic(int n)
        {
            return n;
        }
        __declspec(dllexport) static int ClassStatic(int n)
        {
            return n;
        }
    };

}
这将导致以下DLL导出的函数名:

??ClassNonStatic@MyClass@@AAEHH@Z

??ClassStatic@MyClass@@CAHH@Z

环球基金会

名称空间函数

<> P>有趣的命名与基本上不兼容VisualStudio构建的C++项目。这就是所谓的,将一些类型信息嵌入到名称本身中,作为我所说的导出函数限制的解决方法。从技术上讲,您可以在外部使用这些函数,但它很脆弱,并且依赖于编译器特定行为的细微差别

在DLL中导出函数的经验法则是:你能在C中这样做吗?如果不能,那么几乎可以肯定你会导致问题

请注意,即使使用
extern“C”
,即使是静态类方法(本质上是全局的)也仍然存在名称混乱。但是名称空间中的独立函数导出时不会损坏名称(尽管它们会丢失名称空间范围)

你可以开始明白为什么这个经验法则是有意义的


如果您想导出一个类,让我们遵循经验法则,像在C中那样设计DLL接口。下面是一个示例。让我们来学习C++类:

    class Employee
    {
    private:
        std::string firstName;
        std::string lastName;

    public:
        void SetFirstName(std::string& s)
        {
            this->firstName = s;
        }
        void SetLastName(std::string& s)
        {
            this->lastName = s;
        }
        std::string GetFullName()
        {
            return this->firstName + " " + this->lastName;
        }
    };
您不能将
\uuu declspec(dllexport)
粘在这上面。您必须为它提供一个C接口,并将其导出。像这样:

    extern "C"
    {
        __declspec(dllexport) Employee* employee_Construct()
        {
            return new Employee();
        }

        __declspec(dllexport) void employee_Free(Employee* e)
        {
            delete e;
        }

        __declspec(dllexport) void employee_SetFirstName(Employee* e, char* s)
        {
            e->SetFirstName(std::string(s));
        }

        __declspec(dllexport) void employee_SetLastName(Employee* e, char* s)
        {
            e->SetLastName(std::string(s));
        }

        __declspec(dllexport) int employee_GetFullName(Employee* e, char* buffer, int bufferLen)
        {
            std::string fullName = e->GetFullName();
            if(buffer != 0)
                strncpy(buffer, fullName.c_str(), bufferLen);
            return fullName.length();
        }
    }
然后在C#端编写另一个小包装器,您就成功地完成了这个类

特别是对于封送到C#,另一个选项是为类提供COM接口,而不是C接口。本质上是一样的,但是有很多助手类和特殊编译器支持,在不编写单独的包装器的情况下,将COM支持直接添加到C++类。COM对象可以由C#直接引用


但是,这对ios没有帮助…

您必须使用全局的、C风格的方法。原因是

基本上可以归结为:C函数可以很好地转换为DLL导出,因为C在语言特性方面“更贴近实际”。C更直接地翻译成机器代码。C++在编译器级别上做了很多工作,给了你很多不能在C++环境之外使用的特性。因此,导出的函数应该遵循C样式,以便跨DLL边界正常运行。这意味着没有模板,没有内联代码,没有非POD类或结构

考虑以下代码:

extern "C"
{
    __declspec(dllexport) int GlobalFunc(int n)
    {
        return n;
    }

    namespace SomeNamespace
    {
        __declspec(dllexport) int NamespaceFunction(int n)
        {
            return n;
        }
    }

    class MyClass
    {
        __declspec(dllexport) int ClassNonStatic(int n)
        {
            return n;
        }
        __declspec(dllexport) static int ClassStatic(int n)
        {
            return n;
        }
    };

}
这将导致以下DLL导出的函数名:

??ClassNonStatic@MyClass@@AAEHH@Z

??ClassStatic@MyClass@@CAHH@Z

环球基金会

名称空间函数

<> P>有趣的命名与基本上不兼容VisualStudio构建的C++项目。这就是所谓的,将一些类型信息嵌入到名称本身中,作为我所说的导出函数限制的解决方法。从技术上讲,您可以在外部使用这些函数,但它很脆弱,并且依赖于编译器特定行为的细微差别

在DLL中导出函数的经验法则是:你能在C中这样做吗?如果不能,那么几乎可以肯定你会导致问题

请注意,即使使用
extern“C”
,即使是静态类方法(本质上是全局的)也仍然存在名称混乱。但是名称空间中的独立函数导出时不会损坏名称(尽管它们会丢失名称空间范围)

你可以开始明白为什么这个经验法则是有意义的


如果您想导出一个类,让我们遵循经验法则,像在C中那样设计DLL接口。下面是一个示例。让我们来学习C++类:

    class Employee
    {
    private:
        std::string firstName;
        std::string lastName;

    public:
        void SetFirstName(std::string& s)
        {
            this->firstName = s;
        }
        void SetLastName(std::string& s)
        {
            this->lastName = s;
        }
        std::string GetFullName()
        {
            return this->firstName + " " + this->lastName;
        }
    };
您不能将
\uuu declspec(dllexport)
粘在这上面。您必须为它提供一个C接口,并将其导出。像这样:

    extern "C"
    {
        __declspec(dllexport) Employee* employee_Construct()
        {
            return new Employee();
        }

        __declspec(dllexport) void employee_Free(Employee* e)
        {
            delete e;
        }

        __declspec(dllexport) void employee_SetFirstName(Employee* e, char* s)
        {
            e->SetFirstName(std::string(s));
        }

        __declspec(dllexport) void employee_SetLastName(Employee* e, char* s)
        {
            e->SetLastName(std::string(s));
        }

        __declspec(dllexport) int employee_GetFullName(Employee* e, char* buffer, int bufferLen)
        {
            std::string fullName = e->GetFullName();
            if(buffer != 0)
                strncpy(buffer, fullName.c_str(), bufferLen);
            return fullName.length();
        }
    }
然后在C#端编写另一个小包装器,您就成功地完成了这个类

特别是对于封送到C#,另一个选项是为类提供COM接口,而不是C接口。本质上是一样的,但是有很多助手类和特殊编译器支持,在不编写单独的包装器的情况下,将COM支持直接添加到C++类。COM对象可以由C#直接引用


不过,这对ios没有帮助…

作为旁注,我几天前用mingw/c++做了一个实验,可以为您澄清

我有一个全局参考计数器,用于查找程序中的内存泄漏

class ReferenceCounter /** other implementations details are omitted.*/
{
public:

static int GlobalReferenceCounter;

//version 1
static int getReferenceCount1() { return GlobalReferenceCounter;}

//verison 2
static int getReferenceCount2(); //same code of version 1 but moved into .cpp file
};
当使用引用计数器将我的库编译到DLL中时,将复制变量,将1个版本编译到DLL中,并在客户端代码中编译一个版本

当我从DLL的工厂方法中询问引用计数的数据时,只有DLL中的引用计数器增加/减少。当客户机代码使用从Ref计数器继承的自己的类时,客户机引用计数器将增加/减少

所以为了检查内存泄漏,我必须在程序结束时进行检查