C++;头文件,代码分离 我是C++新手,我有一些关于代码分离的一般性问题。我目前已经在一个文件中构建了一个小应用程序。我现在要做的是将其转换为单独的文件,以便它们包含类似的代码或诸如此类的内容。我现在真正的问题是,我如何知道如何区分事物?代码应该分隔的不可见边距是多少

C++;头文件,代码分离 我是C++新手,我有一些关于代码分离的一般性问题。我目前已经在一个文件中构建了一个小应用程序。我现在要做的是将其转换为单独的文件,以便它们包含类似的代码或诸如此类的内容。我现在真正的问题是,我如何知道如何区分事物?代码应该分隔的不可见边距是多少,c++,header,code-separation,C++,Header,Code Separation,还有,头文件有什么意义?是转发声明方法和类,以便在编译期间链接器包含它们之前,我可以在代码中使用它们吗 任何对方法或最佳实践的洞察都会很好,谢谢 头文件应包含类和函数声明 源文件包含类和函数定义 每个头文件有一个声明,每个源文件有一个定义,这是标准做法(即更容易读取),不过对于小的(读取更简单的帮助器)对象,您有时会将它们与相关的更实质的对象分组 示例:类菜单 头文件包含声明的原因是,您可以从多个源文件中包含声明,因此每个源文件对每个类和函数都有完全相同的定义 这样考虑: 如果没有头文件,则需要

还有,头文件有什么意义?是转发声明方法和类,以便在编译期间链接器包含它们之前,我可以在代码中使用它们吗


任何对方法或最佳实践的洞察都会很好,谢谢

头文件应包含类和函数声明

源文件包含类和函数定义

每个头文件有一个声明,每个源文件有一个定义,这是标准做法(即更容易读取),不过对于小的(读取更简单的帮助器)对象,您有时会将它们与相关的更实质的对象分组

示例:类菜单 头文件包含声明的原因是,您可以从多个源文件中包含声明,因此每个源文件对每个类和函数都有完全相同的定义

这样考虑:

如果没有头文件,则需要在每个源文件中都有类和/或函数声明(没有)定义,这意味着在每个文件中都有相同声明的副本。因此,如果修改一个类,则需要在每个文件中进行相同的修改。通过使用头文件,您可以将声明放在一个位置,因此只需修改一个对象。

决定如何将代码划分为不同的类/函数是编程的主要任务之一。关于如何做到这一点,有很多不同的指导意见,我建议阅读C++和面向对象设计的教程,让你开始。

将提供一些基本准则

  • 把用过的东西放在一起 一起
  • 为域对象创建类 (如文件、收藏等)
头文件允许您声明一个类或函数,然后在几个不同的源文件中使用它。例如,如果在头文件中声明一个类

// A.h
class A
{
public:
    int fn();
};
然后可以在多个源文件中使用此类:

// A.cpp
#include "A.h"
int A::fn() {/* implementation of fn */}

//B.cpp
#include "A.h"
void OtherFunction() {
    A a;
    a.fn();
}
因此,头文件使您能够将声明与实现分开。如果要将所有内容(声明和实现)放在源文件(例如a.cpp)中,那么请尝试将其包含在第二个文件中,例如

// B.cpp
#include  "A.cpp" //DON'T do this!

然后你可以编译B.cpp,但是当你尝试链接你的程序时,链接器会抱怨你有多个定义的对象——这是因为你有A实现的多个副本。

首先,你不应该把任何不需要被任何其他文件(需要它的文件除外)看到的东西放入头中。然后,让我们在下面定义一些我们需要的东西

翻译单位 翻译单元是正在编译的当前代码,包括所有代码 通过它,直接或间接地。一个翻译单元翻译成一个.o/.obj文件

节目 这就是将所有的.o/.obj文件链接到一个二进制文件中,可以 执行以形成一个过程

有不同翻译单位的要点是什么

  • 减少依赖关系,这样,如果更改一个类的一个方法,就不必重新编译程序的所有代码,只需重新编译受影响的翻译单元。一个
  • 通过使用翻译单元本地名称减少可能的名称冲突,这些名称在链接到一起时其他翻译单元不可见
  • 现在,如何将代码拆分为不同的翻译单元?答案是没有“你这样做”,但是你必须根据具体情况来考虑。这一点通常很清楚,因为您有不同的类,这些类可以也应该放在不同的翻译单元中:

    foo.hpp:

    /* Only declaration of class foo we define below. Note that a declaration
     * is not a definition. But a definition is always also a declaration */
    class foo;
    
    /* definition of a class foo. the same class definition can appear 
       in multiple translation units provided that each definition is the same  
       basicially, but only once per translation unit. This too is called the  
       "One Definition Rule" (ODR). */
    class foo {
        /* declaration of a member function doit */
        void doit();
    
        /* definition of an data-member age */
        int age;
    };
    
    /* include the header of it */
    #include "foo.hpp"
    
    /* definition of the member function doit */
    void foo::doit() {
        /* ... */
    }
    
    /* definition of a translation unit local name. preferred way in c++. */
    namespace {
        void help() {
            /* ... */
        }
    }
    
    void getTheAnswer() {
        /* let's call our helper function */
        help();
        /* ... */
    }
    
    /* define answerCheat. non-const objects are translation unit nonlocal  
       by default */
    int answerCheat = 42;
    
    /* so, this is the same as above, just with other classes/files... */
    class bar {
    public:
        bar(); /* constructor */
    }; 
    
    /* we need the foo.hpp file, which declares getTheAnswer() */
    #include "foo.hpp"
    #include "bar.hpp"
    
    bar::bar() {
        /* make use of getTheAnswer() */
        getTheAnswer();
    }
    
    声明一些自由函数和对象:

    /* if you have translation unit non-local (with so-called extern linkage)  
       names, you declare them here, so other translation units can include  
       your file "foo.hpp" and use them. */
    void getTheAnswer();
    
    /* to avoid that the following is a definition of a object, you put "extern"  
       in front of it. */
    extern int answerCheat;
    
    foo.cpp:

    /* Only declaration of class foo we define below. Note that a declaration
     * is not a definition. But a definition is always also a declaration */
    class foo;
    
    /* definition of a class foo. the same class definition can appear 
       in multiple translation units provided that each definition is the same  
       basicially, but only once per translation unit. This too is called the  
       "One Definition Rule" (ODR). */
    class foo {
        /* declaration of a member function doit */
        void doit();
    
        /* definition of an data-member age */
        int age;
    };
    
    /* include the header of it */
    #include "foo.hpp"
    
    /* definition of the member function doit */
    void foo::doit() {
        /* ... */
    }
    
    /* definition of a translation unit local name. preferred way in c++. */
    namespace {
        void help() {
            /* ... */
        }
    }
    
    void getTheAnswer() {
        /* let's call our helper function */
        help();
        /* ... */
    }
    
    /* define answerCheat. non-const objects are translation unit nonlocal  
       by default */
    int answerCheat = 42;
    
    /* so, this is the same as above, just with other classes/files... */
    class bar {
    public:
        bar(); /* constructor */
    }; 
    
    /* we need the foo.hpp file, which declares getTheAnswer() */
    #include "foo.hpp"
    #include "bar.hpp"
    
    bar::bar() {
        /* make use of getTheAnswer() */
        getTheAnswer();
    }
    
    bar.hpp:

    /* Only declaration of class foo we define below. Note that a declaration
     * is not a definition. But a definition is always also a declaration */
    class foo;
    
    /* definition of a class foo. the same class definition can appear 
       in multiple translation units provided that each definition is the same  
       basicially, but only once per translation unit. This too is called the  
       "One Definition Rule" (ODR). */
    class foo {
        /* declaration of a member function doit */
        void doit();
    
        /* definition of an data-member age */
        int age;
    };
    
    /* include the header of it */
    #include "foo.hpp"
    
    /* definition of the member function doit */
    void foo::doit() {
        /* ... */
    }
    
    /* definition of a translation unit local name. preferred way in c++. */
    namespace {
        void help() {
            /* ... */
        }
    }
    
    void getTheAnswer() {
        /* let's call our helper function */
        help();
        /* ... */
    }
    
    /* define answerCheat. non-const objects are translation unit nonlocal  
       by default */
    int answerCheat = 42;
    
    /* so, this is the same as above, just with other classes/files... */
    class bar {
    public:
        bar(); /* constructor */
    }; 
    
    /* we need the foo.hpp file, which declares getTheAnswer() */
    #include "foo.hpp"
    #include "bar.hpp"
    
    bar::bar() {
        /* make use of getTheAnswer() */
        getTheAnswer();
    }
    
    bar.cpp:

    /* Only declaration of class foo we define below. Note that a declaration
     * is not a definition. But a definition is always also a declaration */
    class foo;
    
    /* definition of a class foo. the same class definition can appear 
       in multiple translation units provided that each definition is the same  
       basicially, but only once per translation unit. This too is called the  
       "One Definition Rule" (ODR). */
    class foo {
        /* declaration of a member function doit */
        void doit();
    
        /* definition of an data-member age */
        int age;
    };
    
    /* include the header of it */
    #include "foo.hpp"
    
    /* definition of the member function doit */
    void foo::doit() {
        /* ... */
    }
    
    /* definition of a translation unit local name. preferred way in c++. */
    namespace {
        void help() {
            /* ... */
        }
    }
    
    void getTheAnswer() {
        /* let's call our helper function */
        help();
        /* ... */
    }
    
    /* define answerCheat. non-const objects are translation unit nonlocal  
       by default */
    int answerCheat = 42;
    
    /* so, this is the same as above, just with other classes/files... */
    class bar {
    public:
        bar(); /* constructor */
    }; 
    
    /* we need the foo.hpp file, which declares getTheAnswer() */
    #include "foo.hpp"
    #include "bar.hpp"
    
    bar::bar() {
        /* make use of getTheAnswer() */
        getTheAnswer();
    }
    
    请注意,匿名名称空间中的名称(如上所述)不会发生冲突,因为它们似乎是本地翻译单元。实际上它们不是,它们只是有唯一的名称,这样它们就不会冲突。如果您确实想要(几乎没有理由)转换单元本地名称(例如,因为与c兼容,所以c代码可以调用您的函数),您可以这样做:

    static void help() { 
        /* .... */
    }
    
    ODR还指出,在一个程序中,任何对象或非内联函数的定义不能超过一个(类是类型,而不是对象,因此不适用于它们)。因此,您必须注意不要将非内联函数放入头中,或者不要将“intfoo;”之类的对象放入头中。当链接器尝试将包括这些头的翻译单元链接在一起时,这将导致链接器错误

    我希望我能帮你一点忙。这是一个很长的答案,确实有些地方有错误。我知道翻译单元严格地定义为另一种方式(预处理器的输出)。但我认为将其纳入上述内容不会带来太大的价值,而且会混淆问题。如果你发现了真正的bug,请随时打我一巴掌:)

    建议: 1.现在就为您的应用程序准备好设计。 2.根据设计,创建相互交互的必要对象。 3.重构或完全更改现有代码以适应新创建的设计


    头文件为可能使用其功能的其他类提供接口。

    请注意,结构菜单{int bar;void foo();};是类菜单的定义,但是是成员函数foo的声明,但是是对象成员栏的定义。您的回答听起来像是类MenuAlso的声明,头文件通常包含函数定义。