c++ - c++ 类:编写函数的不同方法
问题描述
以下3种情况有什么区别:
1)在point.h中:
class point
{
int x,y;
public:
int getX();
};
int point::getX() {
return this->x;
}
2)在point.h中:
class point
{
int x,y;
public:
int getX()
{
return this->x;
}
};
3)在point.h中:
class point
{
int x,y;
public:
int getX();
};
诠释点.cpp:
int point::getX() {
return this->x;
}
注意:我读到它以某种方式连接到 inline 但不确定其中哪一个使编译器可以处理int getX()
和inline int getX()
解决方案
避免第一个:
struct point
{
int x,y;
int getX();
};
int point::getX() {
return this->x;
}
如果多个源文件包含point.h
,您将获得 的多个定义point::getX
,从而导致违反单一定义规则(现代链接器将给出错误消息)。
对于第二个:
struct point
{
int x,y;
int getX()
{
return this->x;
}
};
这隐式地内联了函数。这意味着函数定义可以在任何使用它的地方复制粘贴,而不是解析函数调用。这里有一些权衡。一方面,通过在标题中提供定义,您可以更轻松地分发您的库。此外,在某些情况下,由于代码的局部性,您可能会看到性能改进。另一方面,由于指令缓存未命中,您实际上可能会损害性能(更多指令==它不会全部适合缓存)。随着内联函数被复制,二进制文件的大小可能会增加。
另一个权衡是,如果您需要更改您的实现,所有客户端都必须重建。
最后,根据函数的敏感性,您可能会通过标头泄露商业机密(也就是说,绝对没有隐藏您的秘密武器)(注意:总是可以反编译您的二进制文件并逆向工程实现,所以把.cpp 文件中的 def 不会阻止坚定的程序员,但它会让诚实的人保持诚实)。
第三个,将定义分隔为 .cpp 文件:
// point.h
struct point
{
int x,y;
int getX();
};
// point.cpp
int point::getX() {
return this->x;
}
这将导致函数导出到您的库(至少对于 gcc。在 Windows 中,您需要通过使用__declspec
指令来明确地导入/导出)。同样,这里有权衡。
更改实现不需要客户端重新编译;您可以分发一个新库以供他们链接(如果您仅更改 .cpp 文件中的 impl 详细信息,则新库与 ABI 兼容)。但是,分发库更加困难,因为现在需要为每个平台构建二进制文件。
由于需要将函数指针解析为库以运行代码,您可能会看到性能下降。由于您的代码可能对指令缓存更友好,您可能还会看到内联的性能提高。
最后,有很多事情要考虑。我的建议是默认使用#3,除非你正在编写模板。当您想提高性能时,您可以开始衡量内联对您的作用(二进制大小以及运行时性能)。当然,您可能有其他信息使方法#2 或#3 更适合该任务(例如,您有一个 Point 类,并且您知道访问X
将在任何地方发生,并且它是一个非常小的函数,因此您决定内联它)。
推荐阅读
- snort - snort 内容中的 less 符号是什么
- javascript - 我可以导入或需要数学函数,这样就不必在它们前面加上“数学”。每次通话?
- python - 熊猫从多列的年份列表中计算总年数
- python - 如何将 Matlab 中的 listdlg 转换为 Python
- node.js - 为什么我的带有嵌套异步函数的 try-catch 异常没有抛出?
- c# - 检索和使用在 ComboBox 中选择的值
- mongodb - 在 MongoDB 操作中使用变量的值
- android-studio - 从 Android Studio 启动的模拟器上的这些圆圈是什么?
- azure-devops - 检查/了解 Azure Devops 中的构建是由手动还是 CI 触发的最佳方法
- xamarin - 如何从 Xamarin Forms UWP 中删除/替换选择器下拉图标?