首页 > 解决方案 > 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()

标签: c++class

解决方案


避免第一个:

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将在任何地方发生,并且它是一个非常小的函数,因此您决定内联它)。


推荐阅读