Given this current setup, how can I implement this so that I can avoid including any header files in the file.h
header file?
file.h:
#ifndef __FILE_H__
#define __FILE_H__
class foo {
private:
Vector vector; // std::vector from <vector>
Map map; // std::map from <map>
public:
void bar();
};
#endif
file.cpp:
#include "file.h"
void foo::bar()
{
// Do something with private variables...
}
main.cpp
#inclue "file.h"
int main()
{
foo var;
// Do something...
}
CodePudding user response:
Given this current setup, how can I implement this so that I can avoid including any header files in the file.h header file?
Member variables of a class must be defined before definition of the class. You can avoid including any files by defining everything in the file.h file.
Standard types are only defined in standard headers and you cannot avoid including those if you want to use them as members. As such, if you want to avoid including headers, then you have to avoid using standard library.
I suppose you could also avoid including headers by importing modules instead. Standard library isn't modular yet though.
CodePudding user response:
Abstract class or or pimpl-idiom might avoid to have extra #include:
Abstract class:
#include <memory> class fooInterface { public: virtual ~fooInterface() = default; void bar() = 0; }; std::unique_ptr<fooInterface> make_foo();
with
foo
remains the same, but in cpp files with additionalstd::unique_ptr<fooInterface> make_foo() { return std::make_unique<foo>(); }
-
#include <memory> class foo { struct Impl; std::unique_ptr<Impl> impl; public: ~foo(); void bar(); };
and in cpp file:
#include <map> #include <vector> class foo::Impl // Roughly your current `foo` { private: Vector vector; // std::vector from <vector> Map map; // std::map from <map> public: void bar() { /**/} }; foo::~foo() = default; // Here for `foo::~Impl` which should be visible void foo::bar() { return impl->bar(); }
CodePudding user response:
The motivation for doing something like this would be to reduce compilation times by minimising include trees (in this case "file.h" would be pulled in from lots of places, and it will also in turn, pull in lots of other includes). It also improves testability/mockability. Due to the additional complexity, I would only be inclined to use this for "domain level" objects which are accessed via an API (i.e. do not use this where there is sparse usage).
You can effect this by abstracting foo
such that only its API is exposed in the header file. You then implement a subclass which pulls in the includes - but they are only pulled in once.
For more detail I would consult "Large-Scale C Software Design" from John Lakos. Allegedly the older version is better: https://www.amazon.co.uk/Large-Scale-C-Software-Design-APC/dp/0201633620
He has also spoken at various conferences about the new "module" feature: e.g. https://www.youtube.com/watch?v=EglLjioQ9x0
As a bare minimum example you would have the following. Obviously it would be better to return a unique_ptr<foo>
.
file.h
#ifndef _FILE_H_672b47fa_7d02_458a_bd42_4774a3765a1b
#define _FILE_H_672b47fa_7d02_458a_bd42_4774a3765a1b
struct foo {
virtual ~foo() = default;
virtual void bar() = 0;
};
extern foo* fooFactory();
#endif
file.cpp
#include "file.h"
#include <...etc...>
...etc...
class fooImpl : public foo {
private:
Vector vector; // std::vector from <vector>
Map map; // std::map from <map>
...etc...
public:
virtual ~fooImpl() = default;
void bar() override;
};
void fooImpl::bar() {
// Do something with private variables...
}
foo* fooFactory() {
return new fooImpl();
}
main.cpp
#include "file.h"
int main() {
foo* = fooFactory();
// Do something...
delete foo;
}
An alternative approach, as others have pointed out, would be to encapsulate a separate struct containing the "data" via a member pointer. It's a valid approach although it could make const-correctness harder to enforce. It's also related to the flyweight pattern which is useful when the data needs to be passed around different objects, see https://refactoring.guru/design-patterns/flyweight
CodePudding user response:
You generally can if you instead always include the standard header from the C file that uses the class:
#include <vector>
#include <custom_stuff_that_references_std_vector.h>
The definitions from the previously included files remain valid.
Looks like a useful feature to add to the code obfuscator.
CodePudding user response:
You may take a look at this first. What are forward declarations in C ?
private.h
struct fooPrivate
{
Vector vec;
Map m;
}
file.h
struct fooPrivate;
class foo
{
private:
fooPrivate *m_ptr;
};
file.cpp
#include "private.h"
m_ptr = new fooPrivate(); // In constructor
You can avoid including any header files in the file.h
, but you still need to include stl headers in private.h
.