C ++中的常见做法是将.h
(或.hpp
)和实现中的声明分隔为.cpp
。
我知道两个主要原因(也许还有其他原因):
make
从预编译的.o
文件中将其链接起来)class A
的实施取决于class B
以及class B
上class A
的实施)......但我没有这个问题经常发生,我可以解决它。在面向对象编程的情况下,它看起来像这样:
QuadraticFunction.h
:
class QuadraticFunc{
public:
double a,b,c;
double eval ( double x );
double solve( double y, double &x1, double &x2 );
};
QuadraticFunction.cpp
:
#include <math.h>
#include "QuadraticFunc.h"
double QuadraticFunc::eval ( double x ){ return c + x * (b + x * a ); };
double QuadraticFunc::solve( double y, double &x1, double &x2 ){
double c_ = c - y;
double D2 = b * b - 4 * a * c_;
if( D2 > 0 ){
double D = sqrt( D2 );
double frac = 0.5/a;
x1 = (-b-D)*frac;
x2 = (-b+D)*frac;
}else{ x1 = NAN; x2 = NAN; }
};
main.cpp
:
#include <math.h>
#include <stdio.h>
#include "QuadraticFunc.h"
QuadraticFunc * myFunc;
int main( int argc, char* args[] ){
myFunc = new QuadraticFunc();
myFunc->a = 1.0d; myFunc->b = -1.0d; myFunc->c = -1.0d;
double x1,x2;
myFunc->solve( 10.0d, x1, x2 );
printf( "soulution %20.10f %20.10f \n", x1, x2 );
double y1,y2;
y1 = myFunc->eval( x1 );
y2 = myFunc->eval( x2 );
printf( "check %20.10f %20.10f \n", y1, y2 );
delete myFunc;
}
然后使用makefile
编译它,如下所示:
FLAGS = -std=c++11 -Og -g -w
SRCS = QuadraticFunc.cpp main.cpp
OBJS = $(subst .cpp,.o,$(SRCS))
all: $(OBJS)
g++ $(OBJS) $(LFLAGS) -o program.x
main.o: main.cpp QuadraticFunc.h
g++ $(LFLAGS) -c main.cpp
QuadraticFunc.o: QuadraticFunc.cpp QuadraticFunc.h
g++ $(LFLAGS) -c QuadraticFunc.cpp
clean:
rm -f *.o *.x
但是,我发现它经常非常不方便
尤其是当您更改代码时(例如,在您尚未确定整个项目的整体结构时,在开发的初始阶段)。
.cpp
和.h
部分代码之间来回切换。 QuadraticFunc::
),你可以做很多拼写错误和不一致的事情,所以编译器会一直抱怨(我经常犯这样的错误)Makefile
,你在那里做了许多其他错误,这些错误很难从编译器输出中找到(例如我经常忘记编写Makefile所以该代码重新编译我编辑的每个依赖项从这个角度来看,我更喜欢Java的工作原理。出于这个原因,我只是通过将所有代码(包括实现)放在.h
中来编写我的C ++程序。像这样:
#include <math.h>
class QuadraticFunc{
public:
double a,b,c;
double eval ( double x ){ return c + x * (b + x * a ); }
double solve( double y, double &x1, double &x2 ){
double c_ = c - y;
double D2 = b * b - 4 * a * c_;
if( D2 > 0 ){
double D = sqrt( D2 );
double frac = 0.5/a;
x1 = (-b-D)*frac;
x2 = (-b+D)*frac;
}else{ x1 = NAN; x2 = NAN; }
};
};
使用通用默认的makefile,如下所示:
FLAGS = -std=c++11 -Og -g -w
all : $(OBJS)
g++ main.cpp $(LFLAGS) -w -o program.x
(main.cpp
保持不变)
然而,现在当我开始编写更复杂的程序时,编译时间开始很长,当我不得不一直重新编译所有内容时。
有没有办法如何利用make
(更快的编译时间)的优势,仍然以类似Java的方式组织程序结构(一切都在类身体而不是单独的.h
和.cpp
)哪个更方便?
答案 0 :(得分:5)
然而,现在当我开始编写更复杂的程序时,编译时间开始很长,因为我必须一直重新编译所有内容。
分隔标题和类文件的最佳点之一是不必须编译所有内容。
当你有class1.h,class1.cpp,class2.h,class2.cpp,...,classN.h和classN.cpp时,这些头只包含在每个类的编译对象中。因此,如果你的函数的逻辑在class2中发生了变化但你的标题没有,那么你只需要将class2编译成目标文件。然后,您将为生成实际可执行文件的所有目标文件执行链接。链接很快。
如果您正在构建大型复杂程序并发现编辑标题是问题所在,请在编写之前考虑设计您的应用程序。
答案 1 :(得分:1)
简答:不。
答案很长:仍然没有。
要么将所有代码放在头文件中,要么使用两个文件,其中包含标题,源文件自行编译。
我个人对使用两个文件没有任何问题。大多数编辑器支持“双文件视图” - 其中大多数也支持“跳转到定义”。
将所有函数放在类声明中也有另一个副作用,那就是所有函数都标记为内联,这可能导致函数在输出二进制文件中多次生成,如果多个源中包含相同的标题文件。
虽然编译时间,根据我的经验,不是解析的结果,而是编译的代码生成部分 - 通常是.cpp文件 - 所以如果你包含几个大的头文件,很可能不会很重要。
当然使用make
[或类似的东西]和正确定义的依赖项来构建项目。
答案 2 :(得分:1)
C ++是C ++,Java是Java。在.h- und .cpp文件中拆分源代码是C ++语言概念的一部分。如果你不喜欢它,你就不应该使用它。
将所有内容放在一个头文件中与包含.cpp文件(可行但高度不合适)的实际情况相同。 您应该不执行此操作:
示例: WindowsAPI(COM !!),SFML,Boost(部分)(以及很多更多)
你可以在以下时间执行此操作:
示例:提升(部分)
您必须在以下时间执行此操作:
示例: STL(C ++标准模板库)
答案 3 :(得分:0)
首先,由于可重复性,您必须在分离文件中编写实现和定义。有可能将它们放入同一个文件中,但它不可读。编写代码时,请为需要理解代码的下一个贡献者编写代码。这很重要,因为下一个可能是你:)第二个问题是makefile。 Make是为了简化编译过程而不是更快。因此,如果您在任何文件中进行更改,则无需更改ant make文件。感谢make,你不需要一次又一次地编译你的文件。写一次文件,每次都使用。但是如果添加影响编译过程的新代码文件,是的,你必须在makefile中进行更改。您可以在google c ++样式指南中了解有关可读性,编写定义和实现的更多信息以及所有其他样式问题以及gnu make manuel中的makefile。