c ++标题保持理智

时间:2011-05-24 06:39:28

标签: c++ header include

在c ++编码时,我似乎遇到的最大问题是你必须在引用它之前声明一个类。假设我有两个这样的头文件......

那么header1.h

#include "Header2.h"
#include <deque>
#include <string>
#include <iostream>
using namespace std;
class HelloPackage;
class Hello
{
public:
    string Message;
    HelloPackage * Package;
    Hello():Message("")
    {

    }
    Hello(string message, HelloPackage * pack)
    {
        Message = message;
        Package = pack;
    }
    void Execute()
    {
        cout << Message << endl;
        //HelloPackage->NothingReally doesn't exist.
        //this is the issue essentially
        Package->NothingReally(8);
    }
};

Header2.h

#include "Header1.h"
#include <deque>
#include <string>
#include <iostream>
using namespace std;
class HelloPackage
{
public:
    deque<Hello> Hellos;
    HelloPackage()
    {
        Hellos = deque<Hello>();
    }
    int AddHello(string Message)
    {
        Hellos.push_back(Hello(Message,this));
    }
    void ExecuteAll()
    {
        for each(Hello h in Hellos)
            h.Execute();
    }
    int NothingReally(int y)
    {
        int a = 0;
        a += 1;
        return a + y;
    }
}

我想知道的是,有没有优雅的解决方案来处理这些问题?比如c#和java,你不受这种“线性”编译的限制。

3 个答案:

答案 0 :(得分:5)

  1. 使用标题包含“#ifndef / #define / #endif”或“#pragma once”
  2. 将代码放在.cpp中,而不是标题中的内联
  3. ???
  4. 利润
  5. 这对你有用的原因是因为你可以使用你想要引用的类的前向声明而不包括你希望的文件。

答案 1 :(得分:1)

  1. 你缺少包括警卫
  2. 为什么在标题中定义方法?
  3. 除了代码的这些问题,回答你的问题:正常的方法是转发声明类 - 不要在标题中包含标题(除非你必须)。

答案 2 :(得分:1)

如果你遵循一些基本规则,那就完全没有尴尬了。但与例如Java或C#,您必须自己遵循这些规则,编译器和/或语言规范不会强制执行它。

其他答案已经注意到了,但我会在这里回顾一下,所以你将它放在一个地方:

  1. 使用include guards。他们确保您的标题(以及您的类定义)仅包含一次。

  2. 通常,您需要分离方法的声明和实现。这使得头文件更具可重用性,并且会缩短编译时间,因为头文件通常需要比CPP(即实现)文件更少的#includes。

  3. 在标题中,使用前向声明而不是包含。只有在您使用相应类型的名称时才可以这样做,但不需要知道任何“内部”。原因是前向声明只是告诉编译器存在某个名称,而不是它包含的内容。

    这是类Bar的前向声明:

    class Bar;
    
    class Foo {
        void foooh(Bar * b);
    };
    

    在这里,编译器会知道某处有一个Bar,但它不知道它有哪些成员。

  4. 仅在CPP文件中使用“using namespace xyz”,而不是在标题中。

  5. 好的,这是您的示例代码,经过修改以符合这些规则。我只显示Hello类,HelloPackage将相应地分为标题和CPP文件。

    Hello.h(在你的例子中是Header1.h)

    #include <string>
    
    class HelloPackage;
    class Hello
    {
    public:
        Hello();
        Hello(std::string message, HelloPackage * pack);
        void Execute();
    
    private:
        string Message;
        HelloPackage * Package;
    };
    

    HELLO.CPP

    #include "Hello.h"
    
    #include "HelloPackage.h"
    
    using namespace std;
    
    Hello::Hello() : Message("")
    {}
    
    Hello::Hello(string message, HelloPackage * pack)
    {
        Message = message;
        Package = pack;
    }
    
    void Hello::Execute()
    {
        cout << Message << endl;
        // Now accessing NothingReally works!
        Package->NothingReally(8);
    }
    

    可能出现的一个问题是为什么需要包含字符串。难道你不能只转发声明字符串类吗?

    不同之处在于您使用字符串作为嵌入式成员,不使用指向字符串的指针。这没关系,但是它强制你使用#include,因为编译器必须知道你的Hello类中字符串实例需要多少空间。