I have two questions
lets say there is a base class and several derived classes, the derived classes are going to have all of the #include statements (like #include <iostream> etc) and using lines of the base class.
1. is it considered a good practice to write the base class's #include statements and using lines in the in the derived classes h. file anyway?
2.same question regarding composition - class A has an object of class B as a member, is it a good practice to writes Bs#include` statements in A's h. file anyway?
thanks!
I think it is a good practice to have each include file actually #include any of the definitions it needs, so that in your main program, you can #include your most deeply derived class without having to have additional #include statements for the definitions that class needs.
You can have class definitions contain pointers to previously undefined classes, as follows:
class forward_ref;
class myClass :
Public:
myClass(){}
forward_ref* ptr_to_forward_ref;
};
lets say there is a base class and several derived classes, the
derived classes are going to have all of the #include statements (like
#include <iostream> etc) and using lines of the base class.
Not at all.
First of all, you are not supposed to put using lines at top-level scope in header files. This is a common beginners' mistake.
Second, what makes you think the derived class needs all #includes of the base class? The derived-class header file needs to include the base-class header file, and the derived-class implementation file needs to include the derived-class header file.
This already gives you all includes.
base.h:
#include <string>
class Base
{
// ...
virtual std::string f(); // no `using`
};
derived.h:
#include "base.h"
// no need for <string> here
class Derived : public Base
{
// ...
virtual std::string f();
};
derived.cpp:
#include "derived.h"
// no need for <string> here
std::string Derived::f() // could have used `using std::string`
{
// ...
}
Now of course, it's technically possible to actually do it otherwise, in a more complicated fashion, like this:
base.h:
// no <string>?!
class Base
{
// ...
virtual std::string f();
};
derived.h:
#include "base.h" // still no <string>?!
class Derived : public Base
{
// ...
virtual std::string f();
};
derived.cpp:
#include <string> // ah, OK
#include "derived.h"
std::string Derived::f()
{
// ...
}
This works only because the compiler doesn't separately compile header files but only compilation units (~= .cpp files) as a whole, after all includes have been processed.
But talk about horrible programming style. Why would you want to force everyone who derives from your class to include extra headers?
2.same question regarding composition - class A has an object of class B as a member, is it a good practice to writes Bs#include` statements
in A's h. file anyway?
It depends. If A's header needs access to any of B's members, then you have to use an include, and in that case, again, you just include what you need in b.h and let a.h #include "b.h".
If A's header only needs a pointer or a reference to B, or just a return value, then you can use a forward declaration in order to potentially speed up compilation. Of course, speeding up compilation is not something a C++ beginner should care about, because a lot of time will pass until you will be developing software which take hours to build :)
Anyway, for completeness' sake:
a.h:
class B; // forward declaration, no #include
class A
{
// ...
B f();
B *ptr;
B &ref;
};
a.cpp:
#include "a.h"
#include "b.h" // need the include here
B A::f()
{
B obj;
return obj;
}
b.h:
class B
{
// ...
};
In answer to question 2: typically you would include class B's header file in A's header file (so all the includes needed for A will automatically be included).
However, as pointed out in Logicrat's answer, you could alternatively include only a pointer to B in A. In this case you can use a forward declaration of B in A.h instead of including B.h. The downside to this is that all functions that need to make use of B must then go in A.cc (which will definitely have to include B.h). The advantage is that you can greatly reduce the quantity of code in the header files (since each #include copies an entire header file into the current file just before compilation), which can speed up compilation times.
Related
I have been trying to figure out how to forward declare classes across multiple files in C++. I was able to successfully do it with two classes, but doing this across many classes puzzled me. I tried forward declaring all the classes in a header file and including that in all the classes, but I got the error of incomplete classes. I looked into it, but all the solutions seemed unreasonable or confused me. Can you please explain a good way to do it.
If it helps here is some example code of the issue that specifically occurring. Class A is included in Class C, but Class A also includes Class B which holds Class C resulting in an error because Class C has not been declared.
Class Forward Declaration
//Tried "Class Name {};" but that also failed
Class A;
Class B;
Class C;
Class A
//Class A
#include "B.h"
class A{
private:
B b;
public:
void SetBInt(int set) {b.SetInt(set);}
}
Class B
//Class B
#include "C.h"
class B{
private:
C c;
int i = 0;
public:
void SetInt(int set){i = set;}
}
Class C
//Class C
#include "A.h"
class C{
private:
int i = 0;
public:
void SetInt(int set){i = set;}
}
You have to avoid circular dependencies. One common way to avoid them is by pre-declaring the type, and not having any instances or function calls of that type in the header.
You do this by changing instances, such as B b, into references or pointers: B* b. You also have to move any code that uses b into the CPP file, so you can #include "B.h" prior to using it.
For example, instead of
// we'll remove this header's dependency on B shortly
#include "B.h"
class A
{
B b;
public:
A() { b.SetInt(0); }
};
You do something like this:
class B;
class A
{
B *b; // *pointers and &references to a predeclared class are fine.
public:
A();
~A();
};
... and then in A.cpp:
#include "A.h" // ALWAYS include your own header first
#include "B.h"
A::A()
{
// we didn't need to know how big B was until now, when we're about to make one and
// run its constructor. We'll also need to know what functions are available, and the
// types of all its parameters (or lack of parameters).
b = new B();
b->SetInt(0);
}
A::~A()
{
delete b; // for every "new" there must be a "delete"
}
Yes, this would be (much) better with std::unique_ptr<B> b instead of a raw pointer. With a smart pointer we wouldn't need an explicit destructor. I just didn't want to throw too much potentially new stuff at someone still learning.
Alternatively, you could pass a reference into the constructor, and use the member initializer list (you can only set references when they're constructed). This raises problems with "Object Lifetime". If the instance of B you pass in at construction time is destructed before A is done with it, you're program will violently crash (if you're lucky: that way you'll have a good idea of what the problem is) the next time it's used. Best to avoid it till you have considerably more experience under your belt.
Update
The actual context is that I need to create a package to submit to NIST, trying to test a Facial Recognition Algorithm I am working on. The API to use can be found at NIST API and the project to git is at git project
Some code to make a summary of the scenario:
a.h - interface A, composed by pure virtual methods and one static method (frvt11.h at NIST project)
class A {
public:
virtual ~A() {}
virtual void pure_virtual_method_a() = 0;
virtual void pure_virtual_method_b() = 0;
static int static_method();
}
b.h - header file for b.cpp, where interface A's methods are implemented
#include "a.h"
class B : A {
public:
void pure_virtual_method_a();
void pure_virtual_method_b();
static int static_method();
}
b.cpp - Implementation of interface A's methods.
#include "b.h"
void pure_virtual_method_a() {/*implementation*/};
void pure_virtual_method_b() {/*implementation*/};
int static_method() {/*implementation*/};
c.cpp - A file with only a main method and where I want to instantiate an object of B to use its methods.
#include "b.h"
int main(){
B obj;
obj.pure_virtual_method_a();
return 0;
}
Question 1: To instantiate an object of B in c.cpp, do I need to write the header file b.h like above? That seems to be so redundant! It looks like interface A is so unnecessary :-(
Question 2: Is the code presented the right way to implement interface A, and use an object of type B?
Question 3: Do I need to declare a constructor for B in b.h and implement it in b.cpp?
Question 1
You miss a semicolon after the closing curly brace, and it is better to specify that the pure virtual methods you implement in B are marked as override. This allows the compiler to emit warnings in case you forget to change any of the overridden method declarations as soon as the corresponding pure virtual methods in A would change. Thus you will end up with:
#include "a.h"
struct B : public A {
void pure_virtual_method_a() override;
void pure_virtual_method_b() override;
static int static_method();
};
From this it is also clear that for the compiler to be able to declare B as a type, A needs to be declared as well. For example, how would the compiler check the override keyword if it did not yet already have a declaration of A. In case you would not have any overridden virtual methods, A still needs to be known, since the compiler needs to be able to deduce the size of B.
Furthermore, as mentioned in the comments, declaring B as a struct allows you to drop the public keyword, since the default visibility of a struct is public in contrast with private default visibility for a class. This is the only difference between classes and structs in C++. Thus, for interfaces, using structs is more natural.
Question 2
Not completely. b.cpp should look something along the following lines:
#include "b.h"
void B::pure_virtual_method_a() {/*implementation*/};
void B::pure_virtual_method_b() {/*implementation*/};
int B::static_method() {/*implementation*/};
Otherwise, you declare and define three methods in the global namespace, and the linker will complain about undefined references to the three methods of B declared in b.h.
Furthermore, B needs to know how to derive from A, either publicly, protected, or private.
Furthermore, it is a good idea to add include guards to the header files, to prevent the compiler from seeing the same type declaration twice when compiling an object file like a.o or b.o:
#ifndef B_H
#define B_H
#include "a.h"
struct B : public A {
...
};
#endif
Finally, static_method() needs an implementation for A as well, static methods can not be virtual.
Question 3
You do not need to implement a constructor for B necessarily. In case you do not define one, the compiler will generate a default constructor for B. However, in case you define a non-default constructor for A, you will need to define one for B in case you want to construct instances of type B. The constructor can be implemented inline in the header file, or can be defined in b.cpp.
Question 1.
You can use Factory Pattern, then u can add b.h only in Factoru files? and return pointers or smart pointer to A class. For eample, it can be factory function like:
std::unique_ptr<A> getObject(/*params*/)
{
return std::make_unique<B>(/*params*/)
}
And then in c.cpp file:
auto obj = getObject(/*params*/);
obj->pure_virtual_method_a();
Then you can create another implementations of A interface, and return them from factory.
Question 2.
should be class B : public A
and
void B::pure_virtual_method_a() {/*implementation*/};
void B::pure_virtual_method_b() {/*implementation*/};
int B::static_method() {/*implementation*/};
Question 3.
If you need constructor in class A or constructor exactly for class B, you need to define and implement B class constuctor.
for example. We have class A and its derived class; class B. Is it possible to instantiate a pointer of type B in class A?
#ifndef WARRIOR_H
#define WARRIOR_H
#include "CharacterPlayer.h"
class Warrior: public CharacterPlayer
{
public:
virtual void printCharacterName();
};
#endif
however, when i try to instantiate a Warrior pointer or try to include "Warrior.h", it gives me a number of syntax errors.
#ifndef CHARACTERPLAYER_H
#define CHARACTERPLAYER_H
#include "Warrior.h"
class CharacterPlayer
{
public:
Warrior *warriorPntr = nullptr;
virtual void printCharacterName();
};
#endif
You have a circular dependency among your headers: "CharacterPlayer.h" includes "Warrior.h", and "Warrior.h" includes "CharacterPlayer.h". This cannot compile, because the "sentinel" will stop inclusion.
The trick is to forward-declare the Warrior class in the CharacterPlayer instead of including a header:
#ifndef CHARACTERPLAYER_H
#define CHARACTERPLAYER_H
class Warrior; // <<== Here
class CharacterPlayer
{
public:
Warrior *warriorPntr = nullptr;
virtual void printCharacterName();
};
#endif
This is good enough to declare pointers and references to Warrior, but not enough to call methods or instantiate the class.
You need to eventually include the header for Warrior in the cpp file CharacterPlayer.cpp, but that would not lead to any issues, because there is no circular dependency among your headers.
You can, but it's not a good idea.
To do it, simply remove the "#include "Warrior.h" from your second header, and replace it with a declaration of the form "class Warrior;"
As to why it is a bad idea: making a base class contain a pointer to (or an instance of) a derived class is one way (of several) that ensures implementation of the base class depends on implementation of the derived class. Generally speaking, the definition of derived class should depend on the base class, not the reverse, in order to avoid circular dependencies, to allow the base class to be used polymorphically (look up "Liskov Substitution Principle), etc etc.
This means, although it can be done, your design is fundamentally flawed. It would prevent you doing other useful things in future.
Here is the problem. I need to write header file with two classes, say class A and class B.
in class A I have function that uses object of class B and vice versa, i.e. in class B I have function that uses objects of class A.
If A declared first then there would be error that class B has not been declared.
How to deal with it? I try declare function of a class A after declaration of class B:
void classA::myfunc (classB *b);
But I got the error that function myfunc is not declared.
Experienced people in C++, what to do?
Added:
here is a good link about header
If you need a pointer to a class on a header, not the full object, just add a forward declaration, dont include the header of the pointer's class.
I'm sure that you just use pointers to access that classes that one have a reference to another, dont you? You know, because if you use instances, you got a instance looping. Use forward declarations.
Here's a example of how you can use forward declarations:
A.h
class B;
class C;
class D;
class E;
class A {
B* pointer; //To just have a pointer to another object.
void doThings(C* object); //if you just want to tell that a pointer of a object is a param
D* getThings(); //if you wanna tell that a pointer of such class is a return.
E invalid(); //This will cause an error, because you cant use forward declarations for full objects, only pointers. For this, you have to use #include "E.h".
};
To illustrate how can have a class that mentions one that pointers its type:
B.h
class A;
class B {
A* pointer; //That can be done! But if you use a includes instead of the forward declarations, you'll have a include looping, since A includes B, and B includes A.
}
As mentioned by Tony Delroy (Many thanks to him) You should not ALWAYS use this design. It's provided by the C++ compiler, but its not a good practice. The best is to provide reference header, so your code would look like:
A.h
#include "B.fwd.h"
#include "C.fwd.h"
#include "D.fwd.h"
#include "E.fwd.h"
class A {
B* pointer; //To just have a pointer to another object.
void doThings(C* object); //if you just want to tell that a pointer of a object is a param
D* getThings(); //if you wanna tell that a pointer of such class is a return.
E invalid(); //This will cause an error, because you cant use forward declarations for full objects, only pointers. For this, you have to use #include "E.h".
};
and yours forward headers like this:
B.fwd.h:
class B;
In your fwds, you should have your class forward declaration, and any typedefs that comes with it.
I'm not mentioning the #pragma once, or the #ifndef B.H... you know they'll be there :D
Your code would be on a standard defined by <iosfwd> and better to maintain, specially, if they are templates.
Short answer:
class classA;
Then you defined your classB and then the declaration of classA.
This is called forward-declaration, and is there to solve your problem :)
You can try to add a forward declaration of a class before you use it with a ref or ptr.
classA.h:
class classB;
class classA {
void fun(classB * b);
}
classB.h:
class classA;
class classB {
void fun(classA * a);
}
classA.cpp:
#include "classA.h"
#include "classB.h"
...
classB.cpp:
#include "classA.h"
#include "classB.h"
...
The follwing code is compiled in VC++6. I don't understand why I am getting the compilation error C2079: 'b' uses undefined class 'B' for the following code.
Class B Source
#include "B.h"
void B::SomeFunction()
{
}
Class B Header
#include "A.h"
struct A;
class B
{
public:
A a;
void SomeFunction();
};
struct A Header
#include "B.h"
class B;
struct A
{
B b;
};
If I changed class B header to the following, then there will be no error. But the header declaration won't be at the top!
Class B Header with weird header declaration
struct A;
class B
{
public:
A a;
void SomeFunction();
};
#include "A.h"
In order to define a class or struct, the compiler has to know how big each member variable of the class is. A forward declaration does not do this. I've only ever seen it used for pointers and (less often) references.
Beyond that, what you're trying to do here cannot be done. You cannot have a class A that contains an object of another class B that contains an object of class A. You can, however, have class A contain a pointer to class B that contains an object of class A.
B.cpp
#include "B.h"
void B::SomeFunction()
{
}
B.h
#ifndef __B_h__ // idempotence - keep header from being included multiple times
#define __B_h__
#include "A.h"
class B
{
public:
A a;
void SomeFunction();
};
#endif // __B_h__
A.h
#ifndef __A_h__ // idempotence - keep header from being included multiple times
#define __A_h__
#include "B.h"
class B; // forward declaration
struct A
{
B *b; // use a pointer here, not an object
};
#endif // __A_h__
Two points. First, be sure to use some form of idempotence to keep the headers from being included multiple times per compilation unit. Second, understand that in C++, the only difference between classes and structs is the default visibility level - classes use private visibility by default while structs use public visibility by default. The following definitions are functionally equivalent in C++.
class MyClass
{
public: // classes use private visibility by default
int i;
MyClass() : i(13) { }
};
struct MyStruct
{
int i;
MyStruct() : i(13) { }
};
Forward declarations, like
struct A;
or
class A;
Introduce A as an incomplete type and it remains incomplete until end of type's definition is reached. There are things you can do with incomplete types and things you can't. You can
Declare variables (or members) of type "pointer to A" and "reference to A"
Declare functions which take arguments of type A or return type A
You can't
Declare variables (nor members) of type A
Dereference pointers to A or access any members of references to A
Define subclasses of A.
In your code you try to declare struct member of incomplete type. It's illegal. Only pointers and references are allowed.
public:
A a;
You are trying to create the object of A with only forward declaration. Compiler at this moment ( with only forward decl) cannot decide the size of the object A and hence, it cannot allocate memory required for A. So you cannot create objects with only forward decl.
Instead replace with:
A* a;
Pointer or reference to A without A's class definition will work fine.
Two issues jump out at me here.
1: You've written Struct A instead of struct A; note the lower-case "s". Your compiler might consider the equivalent, but I don't think it's standard C++.
You have defined a circular reference between A and B. Each A object must contain a B object, but each B object must contain an A object! This is a contradiction, and will never work the way you want it to. The usual C++ way to solve that problem is to use pointers or references for A::b or B::a (or both).
You alse include A.h from B.h and B.h from A.h. You should at least use preprocessor macros:
#ifndef __A_H__
#define __A_H__
// A.h contents
#endif
so that file won't be included more than once.
If you create an instance of A, that will create an instance of B (member var) which will create an instance of A (member var) which will create an instance of B which will create an instance of A and so on...
The compiler should not allow this since it requires infinite memory.
To solve this, either A or B must use a reference/pointer to the other class.