繁体   English   中英

(避免)在C ++和高效编译中将代码拆分为.cpp和.h

[英](avoid) splitting code to .cpp and .h in C++ and efficient compilation

C ++中的常见做法是将.h (或.hpp )和实现中的声明分隔为.cpp

我知道两个主要原因(也许还有其他原因):

  1. 编译速度(当您只更改一个文件时,您不必重新编辑所有内容,您可以通过预先编译的.o文件中的make链接它)
  2. 前向声明有时是必要的(当class A class B实现依赖于class Bclass A 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

但是,我发现它经常非常不方便

特别是,当您更改代码时(例如,在您尚未确定整个项目的整体结构时,在开发的初始阶段)。

  1. 在对类结构进行重大更改时,您必须在.cpp.h部分代码之间来回切换。
  2. 您在编辑器和项目文件夹中有两倍的文件令人困惑。
  3. 你必须两次写一些信息(比如函数头或QuadraticFunc:: :),你可以做很多拼写错误和不一致的事情,所以编译器会一直抱怨(我经常犯这样的错误)
  4. 每次添加/删除/重命名某个类时,都必须编辑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 )我觉得更方便吗?

但是,现在当我开始编写更复杂的程序时,编译时间开始很长,因为我必须一直重新编译所有内容。

分隔标题和类文件的最佳点之一是您不必编译所有内容。

当你有class1.h,class1.cpp,class2.h,class2.cpp,...,classN.h和classN.cpp时,这些头只包含在每个类的编译对象中。 因此,如果你的函数的逻辑在class2中发生了变化但你的标题没有,那么你只需要将class2编译成目标文件。 那么你会做产生的实际的可执行所有目标文件的链接 链接很快。

如果您正在构建大型复杂程序并发现编辑标题是问题,请在编写之前考虑设计您的应用程序。

简答:不。

答案很长:仍然没有。

您可以将所有代码放在头文件中,也可以使用两个文件,其中包含标头,源文件自行编译。

我个人对使用两个文件没有任何问题。 大多数编辑器支持“双文件视图” - 其中大多数也支持“跳转到定义”。

将所有函数放在类声明中也有另一个副作用,即所有函数都标记为内联,这可能导致在输出二进制文件中多次生成函数(如果多个源文件中包含相同的标头)。

虽然编译时间,根据我的经验,不是解析的结果,而是编译的代码生成部分 - 通常是.cpp文件 - 所以如果你包含几个大标题,那么很可能不会那么重要。

当然使用make [或类似的]与正确定义的依赖项来构建项目。

C ++是C ++,Java是Java。 在.h- und .cpp文件中拆分源代码是C ++语言概念的一部分。 如果你不喜欢它,你不应该使用它。

将所有内容放在一个头文件中与包含.cpp文件(可行但非常不合适)的实际相同。 你不应该这样做:

  • 编写标准类,函数,...
  • 在较大的程序中多次使用代码部分(当你在main.cpp中包含所有内容时会导致重新定义错误)
  • 您希望将部分程序外包到静态/动态库中。 几乎所有可用的库都以这种方式工作。

例子:WindowsAPI的(COM !!),SFML,升压(部分)(以及更多

你可以这样做:

  • 代码执行非常简单的事情,例如位移操作(制作颜色代码),字符串分析,......

示例:提升(部分)

你必须这样做:

  • 创建在编译运行时生成的模板类或函数。 这是.h / .ccp概念的主要和讨论最多的缺点之一,所以你不是第一个对此感到疑惑的人。

示例: STL(C ++标准模板库)

首先,由于可重复性,您必须在分离的文件中编写实现和定义。 有可能将它们放入同一个文件中,但它不可读。 编写代码时,请为需要理解代码的下一个贡献者编写代码。 这很重要,因为下一个可能是你:)第二个问题是makefile。 Make是为了简化编译过程而不是更快。 因此,如果您在任何文件中进行更改,则无需更改ant make文件。 感谢make,你不需要一次又一次地编译你的文件。写一次文件,每次都使用。 但是如果添加影响编译过程的新代码文件,是的,你必须在makefile中进行更改。 您可以在google c ++样式指南中了解有关可读性,编写定义和实现的更多信息以及所有其他样式问题以及gnu make manuel中的makefile。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM