我已经问了一个类似的问题,但这个问题有点不同
我不想为每个简单的c ++类编写.cpp文件。
当我在单个.hpp文件中编写类定义和声明时,链接器会抱怨成员函数的多个定义,这些函数没有在类的主体内部实现或者使用内联键盘定义。
例如,这将起作用,但成员函数将变为内联:
// log.hpp file
#pragma once
#include<iostream>
class log {
private:
static int m_cnt = 0;
public:
void log();
};
inline void log::log() {
std::cout << ++m_cnt << std::endl;
}
所以我使用模板来摆脱链接器投诉,并希望成员函数不会内联(是吗?):
// log.hpp file
#pragma once
#include<iostream>
template<typename T>
class log_t {
private:
static int m_cnt = 0;
public:
void log();
};
template<typename T>
void log_t<T>::log() {
std::cout << ++m_cnt << std::endl;
}
// some random type (int)
typedef log_t<int> log;
然后我可以简单地在多个.cpp文件中使用日志类而不会有链接器投诉。
即使我使用此方法,成员函数也会成为内联函数吗?
答案 0 :(得分:5)
通常,在头文件中使用每个实现都是一个不好的想法,因为它可能导致较大项目的编译时间非常长。使用模板来避免这种情况也不是一个好主意,因为它不会改变这一事实。
inline
只是对编译器的一个提示;它可能会忽略它并内联您的模板代码。简而言之:你的问题的答案无关紧要。标准/最佳方法是使用.cpp文件进行实现,即使您想避免它。
答案 1 :(得分:5)
虽然将所有内容放在一个.h
文件中通常是不好的做法,但有些情况下这样做会更方便。特别是在定义小类时,以及在原型设计阶段,代码可以快速改变很多。
我真的不建议使用模板来解决链接问题,因为它会减慢编译速度并导致混淆:它就像创建一个函数,当你除了那个参数总是具有相同的值。无论如何,键入inline
比template<typename T>
;)
因此,您必须在类体中定义方法,或者如果在体外定义,则使用inline
注释它们。这是等效的,因为C ++会自动将inline
添加到类体中定义的方法。
您的担忧似乎与生成的代码有关,您可能想知道二进制文件是否会增长太多。但是无论inline
注释如何,一切都很酷,编译器查看每个函数调用并决定是内联还是生成调用。这意味着有时可以内联相同的函数(如果在循环中调用),有时也可以调用。
不同的编译器具有不同的启发式,但inline
关键字对编译器的决定没有特别强烈的影响。您可以使用__forceinline
或__attribute__((always_inline))
之类的内容来强烈要求内联函数,但即使这样,也无法保证对函数的所有调用都将被内联。相反,您可能会对__attribute__(noinline)
for gcc感兴趣,它会(几乎)从不内联电话:
inline __attribute__(noinline) void log::log() // gcc
{
std::cout << ++m_cnt << std::endl;
}
如果您想真正了解代码中发生了什么,可以使用-Winline
查看inline
函数何时未内联。
您还可以使用-Os
或-Oz
优化级别来更改内部编译器阈值,以便减少内联。