Как я могу использовать класс из заголовочного файла в исходном файле, используя extern, но не #include?

Я получил эту ошибку много раз раньше. И я уверен, что все программисты PHP по крайней мере однажды получили эту ошибку. Чтобы решить эту ошибку, вы можете решить использовать решение по вашему уровню проблемы:

Возможное решение 1:

Возможно, вы оставили пробелы до или после (в конце файла после?>) ie

THERE SHOULD BE NO BLANK SPACES HERE

DO CHECK FOR BLANK SPACES HERE AS WELL; THIS LINE (blank line) SHOULD NOT EXIST.

В большинстве случаев это должно решить вашу проблему. Проверьте все файлы, связанные с файлом require.

Примечание: Иногда EDITOR (IDE), например gedit (редактор linux по умолчанию), добавляет одну пустую строку в файл save save. Этого не должно быть. Если вы используете linux. вы можете использовать редактор VI для удаления пробела / строк после?> в конце страницы.

Если это не ваш случай, тогда вы можете использовать ob_start для буферизации вывода, как показано ниже:

Возможное решение 2:

 

Это приведет к буферизации вывода и ваши заголовки будут созданы после буферизации страницы.

-9
задан GEOCHET 1 July 2009 в 01:37
поделиться

10 ответов

Просто чтобы уточнить. Невозможно extern класса:

class Outside
{
    public:
        Outside(int count);
        GetCount();
}

Но если у вас есть класс, доступный в framework.cpp, вы МОЖЕТЕ extern объект типа Outside . Вам понадобится файл .cpp, объявляющий эту переменную:

#include "outside.h"

Outside outside(5);

И затем вы можете ссылаться на этот объект в другом файле через extern (если вы связываете правильный объектный файл при компиляции проекта ):

#include "outside.h"

extern Outside outside;
int current_count = outside.GetCount();

extern используется, чтобы сказать: «Я ЗНАЮ переменная этого типа с таким именем будет существовать, когда эта программа будет запущена, и я хочу ее использовать». Он работает с переменными / объектами, а не с классами, структурами, объединениями, определениями типов и т. Д. Он не сильно отличается от статических объектов.

Возможно, вы думаете о прямом объявлении классов, чтобы сократить время компиляции, но на это есть ограничения (вы можете использовать объекты только как непрозрачные указатели и не можете вызывать для них методы).

Вы также может означать скрытие реализации За пределами от пользователей. Для этого вам нужно будет прочитать о шаблоне PIMPL.


Обновление

Одна из возможностей - добавить бесплатную функцию в Outside.h (я также добавил пространство имен):

namespace X {
    class Outside {
        int count_;
        public:
            Outside(int count) : count_(count) { }
            int GetCount()
            {
                return count_;
            }
    };

    int GetOutsideCount(Outside* o);
}

Реализуйте эту функцию в файле .cpp. Пока вы это делаете, вы также можете сделать глобальную переменную, которую вы намереваетесь, в extern (обратите внимание, сама переменная не обязательно должна быть указателем):

#include "outside.h"

namespace X {
    int GetOutsideCount(Outside* o)
    {
        return o->GetCount();
    }
}

X::Outside outside(5);

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

namespace X {
    class Outside;
    int GetOutsideCount(Outside* o);
}

extern X::Outside outside;

int main()
{
    int current_count = GetOutsideCount(&outside);
}

Я считаю это, мягко говоря, мерзостью. Ваша программа найдет функцию GetOutsideCount , вызовет ее, передав ей Outside * . Outside :: GetCount фактически компилируется в обычную функцию, которая принимает секретный объект Outside (внутри Outside :: GetCount , на этот объект ссылаются через ] this указатель), поэтому GetOutsideCount найдет эту функцию, и указать ему разыменовать Outside * , который был передан в GetOutsideCount . Я думаю, это называется «пройти долгий путь».

Но это то, что есть.

Если вы не состоите в браке с использованием ключевого слова extern , вы можете вместо этого пойти полным ходом » давайте использовать C ++, как это C "режим, добавив следующие две функции таким же образом (то есть через форвардные объявления и реализацию прямо рядом с int GetOUtsideCount () :

Outside* CreateOutsidePointer(int count)
{
    return new Outside(count);
}

void DestroyOutsidePointer(Outside* o)
{
    return delete o;
}

Я больше хочу проглотить Это очень похоже на стратегию, используемую APR .

5
ответ дан 6 September 2019 в 19:22
поделиться

Все здесь слишком мягкие. Нет АБСОЛЮТНО НИКАКОЙ ПРИЧИНЫ, по которой вы не хотели бы включать файл .h.

Сделайте это и включите файл!

6
ответ дан 6 September 2019 в 19:22
поделиться

вы не можете extern класса, но вы можете extern функция, которая создает экземпляр .. В коде потребителя:

class Outside;

extern Outside* MakeAnOutside(int count);
extern int GetOutsideCount(Outside* outside);

Затем в external.h:

Outside* MakeAnOutside(int count)
{
   return new Outside(count);
}

int  GetOutsideCount(Outside* outside)
{
  return outside->GetCount();
}

но .. это может плохая идея ..

3
ответ дан 6 September 2019 в 19:22
поделиться

You don't make classes extern. Just include "outside.h" and create an instance of Outside.

4
ответ дан 6 September 2019 в 19:22
поделиться

Включаемые файлы предназначены для определений, включая определения классов. extern предназначен для переменных.

Если у вас нет определения класса в исходном файле, единственное, что вы можете сделать с ним, - это объявить его с помощью class Outside; и передавать экземпляры по указателю. На самом деле вы ничего не можете сделать с экземплярами, включая создание, разрушение или вызов функций-членов, таких как GetCount () . Для этого вам вообще не нужен extern ; только если вы хотите сослаться на переменную в другом исходном файле, и это не позволит вам сделать с ней что-либо дополнительно.

Нет веской причины не использовать здесь #include . Единственная альтернатива - скопировать и вставить файл заголовка в исходный файл, и это значительно хуже. Любой, кто говорит вам не использовать #include , не понимает C ++, и, очевидно, тот, кто думает, что extern имеет здесь какое-то отношение, определенно не имеет значения.

Если это вообще возможно, вы должен получить опытного разработчика C ++, который поможет вам в обучении, установит хорошие стили кодирования и научит вас, как разрабатывать C ++. Я подозреваю, что вы занимаетесь другими делами, которые позже окажутся плохими идеями.

Любой, кто говорит вам не использовать #include , не понимает C ++, и, очевидно, тот, кто думает, что extern имеет здесь какое-то отношение, определенно не имеет значения.

Если это вообще возможно, вы должен получить опытного разработчика C ++, который поможет вам в обучении, установит хорошие стили кодирования и научит вас, как разрабатывать C ++. Я подозреваю, что вы занимаетесь другими делами, которые позже окажутся плохими идеями.

Любой, кто говорит вам не использовать #include , не понимает C ++, и, очевидно, тот, кто думает, что extern имеет здесь какое-то отношение, определенно не имеет значения.

Если это вообще возможно, вы должен получить опытного разработчика C ++, который поможет вам в обучении, установит хорошие стили кодирования и научит вас, как разрабатывать C ++. Я подозреваю, что вы занимаетесь другими делами, которые позже окажутся плохими идеями.

3
ответ дан 6 September 2019 в 19:22
поделиться

Если у вас было глупое требование, что #include не разрешено, вам придется скопировать и вставить объявление класса в свой .cpp файл. Надо ли говорить, что это было бы очень плохой идеей?

В чем причина этого требования? Мне больно советовать вам, как это сделать. Если вы пытаетесь избежать длинных путей #include в исходных файлах, это проблема сборки, а не проблема исходного кода.

Вам следует добавить каталоги в путь включения с помощью gcc - Вариант I или аналогичный вариант для вашего компилятора.

Если вы действительно, действительно уверены в этом, вам понадобится что-то вроде этого:

framework.cpp

// FIXME: Should #include "outside.h" but not allowed.
class Outside
{
   public:
       Outside(int count);
       GetCount();

       // Omitted
       // void SomeUnusedMethod();
};

<code for framework.cpp here>

void UseOutside()
{
    Outside o(5);
    std::cout << o.GetCount() << std::endl;
}

Тогда я настоятельно рекомендую вам оставить декларацию как есть » просто скопированы и вставлены из файла заголовка. Но если вы хотите обрезать его, вы можете опустить любые невиртуальные методы, которые вы не используете. Вам нужно будет сохранить все переменные.

2
ответ дан 6 September 2019 в 19:22
поделиться

Вы можете использовать $ ("# elementID"). Height () == 0, так как вы знаете, что он будет либо вверх, либо вниз. Это может быть быстрее, чем выполнение .is (": visible"), но я не тестировал этот факт.

sqlservercentral.com/articles/T-SQL/66097/)[1231 visibleDocumentation

  • Создание диаграмм базы данных
  • Создание словаря данных

Нормализация и ссылочная целостность

  • Максимальное использование первичных ключей одного столбца насколько возможно. При необходимости используйте уникальные ограничения.
  • Ссылочная целостность будет всегда соблюдаться
  • Избегать ON DELETE CASCADE
  • OLTP должен быть не менее 4NF
  • Оценивать каждое отношение «один ко многим» как потенциальное «многие ко многим» отношение
  • Первичные ключи, не созданные пользователем
  • Построение Модели на основе вставки вместо обновлений
  • От PK до FK должно быть то же имя (Employee.EmployeeId - это то же поле, что и EmployeeSalary.EmployeeId)
  • За исключением случаев, когда есть двойное соединение (Person.PersonId присоединяется к PersonRelation.PersonId_Parent и PersonRelation.PersonId_Child)

Обслуживание:

2
ответ дан 6 September 2019 в 19:22
поделиться

Поместите включение для вашего класса Outside в StdAfx.h или любой другой заголовочный файл, который framework.cpp уже включает.

2
ответ дан 6 September 2019 в 19:22
поделиться

Я думаю, вы неправильно понимаете классы хранения, и один из них является внешним.

" Объекты и переменные объявлены как ] extern объявляет объект, который определен в другой единице перевода или во включающей области видимости как имеющий внешнюю связь. "

Таким образом, маркировка extern предназначена для переменных, а не для определения / объявления классов

Итак, если вы не можете включить .h, я рекомендую вам создать .h и .cpp как статические библиотеки или dll и использовать их в своем коде

1
ответ дан 6 September 2019 в 19:22
поделиться

Ура ... мы помещаем классы в файлы заголовков и используем #include, чтобы дублировать объявления классов (или других) в несколько файлов cpp ( называемые единицами компиляции).

Если вы действительно не можете использовать #include, у вас остается ручная копия, как было предложено выше, которая имеет очевидную проблему устаревания, когда кто-то изменяет оригинал. Это полностью нарушит ваш тестовый код с трудностями для отслеживания сбоев.

Если вы настаиваете на продолжении этой ручной копии, вам действительно нужно полное объявление класса. Технически вы можете опустить определенные фрагменты, но это плохая идея - очевидно, что ваша команда не имеет глубокого понимания конструкций C ++, поэтому вы вы можете сделать ошибку. Во-вторых, объектная модель C ++ не стандартизирована для компиляторов. Теоретически даже простой невиртуальный метод может изменить модель, нарушив ваш тест.

«Длинный путь» на самом деле не является серьезной причиной не включать файл напрямую. Но если вы действительно не можете, скопируйте весь файл заголовка туда, где мог бы быть #include - именно это и будет делать препроцессор C.

1
ответ дан 6 September 2019 в 19:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: