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); }; }
所有方法都是静态的,静态方法有很多限制,所以我的问题是,如果没有静态方法,如何实现相同的方法?我是否总是需要在DLL中使用静态方法?我想在C#和IOS应用程序中导入此DLL。您必须使用全局的C风格方法。原因是 基本上可以归结为:C函数可以很好地转换为DLL导出,因为C在语言特性方面“更贴近实际”。C更直接地翻译成机器代码。C++在编译器级别上做了很多工作,给了你很多不能在C++环境之外使用的特性。因此,导出的函数应该遵循C样式,以便跨DLL边界正常运行。这意味着没有模板,没有内联代码,没有非POD类或结构 考虑以下代码: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
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计数器继承的自己的类时,客户机引用计数器将增加/减少
所以为了检查内存泄漏,我必须在程序结束时进行检查