C++ 中的常见做法是将.h
(or .hpp
) 中的声明和实现分离到.cpp
.
我知道两个主要原因(也许还有其他原因):
- 编译速度(当您只更改一个文件时,您不必重新编译所有内容,您可以
make
从预编译.o
文件中链接它) - 前向声明有时是必要的(当实现
class A
取决于class B
和实现class B
on 时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
. 像这样:
#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; }
};
};
使用通用默认生成文件,如下所示:
FLAGS = -std=c++11 -Og -g -w
all : $(OBJS)
g++ main.cpp $(LFLAGS) -w -o program.x
(main.cpp
保持不变)
然而,现在当我开始编写更复杂的程序时,编译时间开始变得相当长,因为我必须一直重新编译所有内容。
有什么方法可以利用make
(更快的编译时间)的优势,并且仍然以类似 Java 的方式组织程序结构(所有内容都在类主体中,而不是单独的.h
和.cpp
),我觉得这更方便?