Как работать с extern в разных файлах - PullRequest
0 голосов
/ 03 мая 2020

У меня есть структура этих файлов:

main. cpp

#include "main.h"
Map map;
Fruit fruit;
Stone stone;

main.h

extern Map map;
extern Fruit fruit;
extern Stone stone;

map.h

#include "main.h"
class Map {public: int size = 20;};

fruit.h

#include "main.h"
class Fruit { public: int pos = 1; draw() {return map.size;} };

stone.h

#include "main.h"
class Stone { public: draw() {return map.size * fruit.pos;} };

Проблема в том, что я пытаюсь использовать map.size и fruit.pos Я получаю ошибку:

'map': undeclared identifier

То же самое с stone. Итак, что не так?

Ответы [ 2 ]

2 голосов
/ 03 мая 2020

main.h должно включать map.h, а не наоборот.

main.h должно включать fruit.h, а не наоборот.

main.h должно включать stone.h не наоборот.

Также вы должны добавить включить охрану в заголовочные файлы.

РЕДАКТИРОВАТЬ

Вот один способ, который работает, ( Не могу поверить, что рекомендую такой код, но все же)

// map.h
#ifndef MAP_H
#define MAP_H
class Map {public: int size = 20};
extern Map map;
#endif

// fruit.h
#ifndef FRUIT_H
#define FRUIT_H
#include "map.h"
class Fruit { public: int pos = 1; draw() {return map.size;} };
extern Fruit fruit;
#endif

// stone.h
#ifndef STONE_H
#define STONE_H
#include "map.h"
#include "fruit.h"
class Stone { public: draw() {return map.size * fruit.pos;} };
extern Stone stone;
#endif

// main.cpp
#include "map.h"
#include "fruit.h"
#include "stone.h"
Map map;
Fruit fruit;
Stone stone;

Это не то, как вы должны писать код.

0 голосов
/ 03 мая 2020

Файлы (*.h или *.cpp) должны содержать только те файлы, от которых они напрямую зависят.

Файлы не должны содержать файлы, от которых они не зависят.

Один способ Разорвать циклические зависимости - поместить реализацию в исходный файл foo.cpp вместо встроенного в заголовочный файл foo.h.

Один из способов разорвать зависимости от глобальных переменных - вместо этого передать их как параметры вместо жестко запрограммировав их в подпрограммах.

Использование предварительного объявления можно использовать, чтобы избежать включения заголовочного файла, который используется только для объявления типа. Только когда детали типа, такие как его методы и площадь, не важны. Увы, предварительные объявления для шаблонных классов сложнее.

Для файлов в примере OP приведена альтернативная реализация, включающая эти предложения.

fruit.h

#ifndef FRUIT_H
#define FRUIT_H

class Map;

class Fruit {
public:
    int pos = 1;
    auto draw(Map const&) -> int;
};

#endif

map.h

#ifndef MAP_H
#define MAP_H

class Map {
public:
    int size = 20;
};

#endif

stone.h

#ifndef STONE_H
#define STONE_H

class Fruit;
class Map;

class Stone {
public:
    auto draw(Map const& map, Fruit const& fruit) -> int;
};

#endif

фрукт. cpp

// Identity.
#include "fruit.h"

// Other dependencies.
#include "map.h"

auto Fruit::draw(Map const& map) -> int {
    return map.size;
}

камень. cpp

// Identity.
#include "stone.h"

// Other dependencies.
#include "fruit.h"
#include "map.h"

auto Stone::draw(Map const& map, Fruit const& fruit) -> int {
    return map.size * fruit.pos;
}

основной. cpp

#include <iostream>
#include "fruit.h"
#include "map.h"
#include "stone.h"

using std::cout;

int main() {
    auto map = Map{};
    auto fruit = Fruit{};
    auto stone = Stone{};
    map.size = 17;
    fruit.pos = 3;
    cout << "map.size is " << map.size << "\n";
    cout << "fruit.pos is " << fruit.pos << "\n";
    cout << "fruit.draw(map) is " << fruit.draw(map) << "\n";
    cout << "stone.draw(map, fruit) is " << stone.draw(map, fruit) << "\n";
}
...