I have a project consisting of several files. This is their interdependency:
Header interdependencies
1 2 3 4 5 6 7 8 9 10
|
main.cpp -> all below
io.h -> classes.h
classes.h -> globals.h, io.h, colmanip.h, console.h
console.h -> none
colmanip.h -> none
globals.h -> none
glossary.h -> globals.h, classes.h
locale.h -> globals.h
vector -> none
word.h -> globals.h
|
I know that to avoid identifiers not being recognised I need to forward declare my definitions (and sometimes variables using extern). Relevant header where I forward declare/put my prototypes is
io.h (definitions reside in
io.cpp).
I will try to distill all the code to the most important parts and omitt those unimportant.
io.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
#ifndef IO_H
#define IO_H
#include <needed-stuff>
#include "classes.h" // for ent::lib_entry & ent::save_entry classes used in prototypes below\
// io.cpp is linked with io.h by including io.h
// ...... relevant function prototypes, defined in io.cpp
bool read_file_library(std::ifstream& stream, std::vector<ent::lib_entry>& vector_glossaries); // lib_entry defined in classes.h yet - UNDECLARED IDENTIFIER
char press_button();
bool is_number(const std::string& check_string);
bool if_secure_open(std::ifstream& stream, const std::string dir, const int message_if_fail);
size_t lines_count(std::ifstream& stream);
#endif
|
Some other relevant parts of code, namely
colmanip.h (which doesn't have its .cpp counterpart and changes text colour) and
globals.h (where I keep const/non-const vars for many files to use):
colmanip.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
/*Header file to colour text and background in windows console applications
code snippet by Eklavya Sharma, cplusplus.com/articles/Eyhv0pDG
Global variables - textcol,backcol,deftextcol,defbackcol,colourprotect*/
#pragma once // use pragma, include guards or both? I guess neither actually protects the code from being included in different files (just from multiple inclusions in one file).
#ifndef _INC_EKU_IO_CONCOL
#define _INC_EKU_IO_CONCOL
#include <needed-stuff>
// no accompanying colmanip.cpp, all code is here
namespace colourmanip
{
#ifndef CONCOL
#define CONCOL
enum concol
{
// ...
};
#endif //CONCOL
// globals defined like so
HANDLE std_con_out;
// inline functions supposedly protect me from multiple definition error
inline void update_colours()
{
// ...
}
template<class elem, class traits>
inline std::basic_ostream<elem, traits>& operator<<(std::basic_ostream<elem, traits>& os, concol col)
{
// ...
}
} //end of namespace eku
#endif //_INC_EKU_IO_CONCOL
|
globals.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
#ifndef GLOBALS_H
#define GLOBALS_H
#include <needed-stuff>
// globals.cpp is linked with globals.h by including globals.h
// I think constants have interal-linkage by default, is it true? Should I make them "const char" and move definitions to globals.cpp?
const char [100] sth = "...........";
// ......
// non-constants have external-linkage by default if they appear in file scope, so I guess extern is not needed here?
extern int settings[SETT_OPTION_COUNT]; // defined in globals.cpp
// enum definitions within namespaces to avoid ambiguity
namespace error {
enum save_error {
....
};
}
// ......
// struct definitions like so
struct glossary {
// .....
};
// ......
#endif GLOBALS_H
|
I also have some classes that have global scope and their definitions are located in
classes.h. However, problem arises when I want to do either of these things:
1. Call functions inside the class definition (like if_secure_open() - see code comments)
2. Use newly defined classes in function prototypes (like read_file_library() in io.h - see code comments)
(other questions that arose during writing this code are included in the code comments, please look at them as well, thank you kindly :) )
classes.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
#ifndef CLASSES_H
#define CLASSES_H
#include <needed-stuff>
#include "globals.h" // FORWARD DECLARATIONS OF struct glossary
#include "io.h" // FORWARD DECLARATIONS/PROTOTYPES OF if_secure_open() USED IN ent::lib_entry.get_data()
#include "colmanip.h" // CONSOLE COLOUR MANIPULATION USED IN ent::lib_entry.format_content();
#include "console.h" // forward declarations of simple functions like console_width() or reset_stream()
// no accompanying classes.cpp, all code is here
namespace ent {
class lib_entry {
public:
// couple of variables, most relevant one:
glossary var; // structure from globals.h
void get_data(std::ifstream& stream, lib_entry& entry) {
std::getline(stream, entry.data.name);
std::ifstream f_line_count;
if (if_secure_open(f_line_count, entry.data.name, NULL)) { // if_secure_open as identifier not found - I INCLUDED io.h where it is forward declared!
// ....
}
else {
entry.data.status = error::save_error::not_found;
}
}
std::ostringstream* format_content(lib_entry& entry, unsigned int cardinal, unsigned int columns) {
// ...
std::ostringstream oss;
oss << colourmanip::red << "...."; // colourmanip namespace from colmanip.h
pressbutton(); // function forward declared/prototyped in io.h
// ...
}
};
class save_entry {
public:
// some vars ...
error::save_error internal_error; // again, enum error::save_error defined in globals.h
void get_data(std::ifstream& stream, save_entry& entry) {
// .....
if (entry.internal_error != error::save_error::corrupted) {
for (int u = 1; u < SAVE_DATA_COUNT; u++) {
if (is_number(temp_str[u])) { // is_number forward declared in io.h and defined in io.cpp - yet IDENTIFIER UNKNOWN
entry.vals[u - 1] = stoi(temp_str[u]);
}
}
}
}
};
}
#endif CLASSES_H
|
At some point I tried to move class definitions to its own .cpp file and leave only this in the header:
1 2
|
class lib_entry;
class save_entry;
|
as forward declarations, but it produced even more errors.
I would presume that including a header in another file is almost identical to physically copying the content of the header into a file, so those forward declarations
should work, even if they are pasted into several files that use them (#pragma once doesn't protect against such pasting).
Those are some relevant errors I get while compiling (there are too many to show and some may stem from previous errors)
errrors
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
1
|
1>word.cpp
1>c:\users\pawil\documents\visual studio 2017\projects\one\one\classes.h(25): error C3861: 'if_secure_open': identifier not found
1>c:\users\pawil\documents\visual studio 2017\projects\one\one\classes.h(26): error C3861: 'lines_count': identifier not found
1>c:\users\pawil\documents\visual studio 2017\projects\one\one\classes.h(92): error C3861: 'is_number': identifier not found
1>main.cpp
1>c:\users\pawil\documents\visual studio 2017\projects\one\one\io.h(15): error C2653: 'ent': is not a class or namespace name
1>c:\users\pawil\documents\visual studio 2017\projects\one\one\io.h(15): error C2065: 'lib_entry': undeclared identifier
1>c:\users\pawil\documents\visual studio 2017\projects\one\one\io.h(15): error C2923: 'std::vector': 'lib_entry' is not a valid template type argument for parameter '_Ty'
1>c:\users\pawil\documents\visual studio 2017\projects\one\one\io.h(15): error C3203: 'allocator': unspecialized class template can't be used as a template argument for template parameter '_Alloc', expected a real type
1>c:\users\pawil\documents\visual studio 2017\projects\one\one\main.cpp(43): error C2664: 'bool read_file_library(std::ifstream &,std::vector &)': cannot convert argument 2 from 'std::vector<ent::lib_entry,std::allocator<_Ty>>' to 'std::vector &'
1> with
1> [
1> _Ty=ent::lib_entry
1> ]
1>c:\users\pawil\documents\visual studio 2017\projects\one\one\main.cpp(84): error C2039: 'score': is not a member of 'ent::lib_entry' |