заголовки с ++ сохраняют в здравом уме - PullRequest
1 голос
/ 24 мая 2011

Самая большая проблема, с которой я сталкиваюсь при кодировании на 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 ]

5 голосов
/ 24 мая 2011
  1. Используйте заголовок, включающий охрану, либо "#ifndef / #define / #endif", либо "#pragma Once"
  2. Поместите свой код в .cpp, а не в строку в заголовке
  3. ???
  4. Прибыль

Причина, по которой это будет работать для вас, заключается в том, что вы можете использовать предварительные объявления класса, на который вы хотите сослаться, без включения файла, если хотите.

1 голос
/ 25 мая 2011

Если вы следуете нескольким основным правилам, это совсем не неловко. Но по сравнению, например, с Java или C #, вы должны следовать этим правилам самостоятельно, спецификация компилятора и / или языка не соблюдает его.

Другие ответы уже отмечали это, но я повторю здесь, чтобы вы имели это в одном месте:

  1. Использование включает охрану . Они удостоверяются, что ваш заголовок (и, следовательно, ваше определение класса) включается только один раз.

  2. Обычно вам нужно разделить объявление и реализацию ваших методов. Это делает файлы заголовков более пригодными для повторного использования и сократит время компиляции, поскольку заголовок обычно требует меньше #include, чем файл CPP (т.е. реализация).

  3. В заголовке используйте предварительные объявления вместо include. Это возможно только в том случае, если вы просто используете имя соответствующего типа, но не должны знать какие-либо «внутренние компоненты». Причина этого в том, что предварительное объявление просто сообщает компилятору, что существует определенное имя, но не то, что оно содержит.

    Это предварительное объявление класса Bar:

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

    Здесь компилятор узнает, что где-то есть Bar, но не знает, какие члены у него есть.

  4. Используйте «using namespace xyz» только в файлах CPP, но не в заголовках.

Хорошо, вот ваш пример кода, модифицированный для соответствия этим правилам. Я только показываю класс 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.

1 голос
/ 24 мая 2011
  1. Вам не хватает включить охрану
  2. зачем определять методы в заголовке?

Помимо этих проблем с вашим кодом, чтобы ответить на ваш вопрос: обычный способ - это объявить классы вперед - не включать заголовки в заголовки (если нет необходимости).

...