C++ nested class instances - c++

What I have is 2 classes:
A.h:
#include "B.h"
class A
{
vector<B*> arr;
void Update(int32 id){...};
}
B.h
#include "A.h"
class B
{
int32 id;
A* parent;
void OnRemove()
{
...
parent->Update(id);
}
}
With that logic everything must work fine as expected.
But it won't because of loop include: A.h including B.h and B.h including A.h
The question is how to make it working with that structure of code or other.
Main feature that should exist is to call event in A object which is holding B object.
Every help would be appreciated.

Forward declare class A; in B.h and class B; in A.h
You should then move the implementation of onRemove() to B.cpp and include A.h here.
Also don't forget your include guards. Example:
#ifndef _A_H_
#define _A_H_
class B;
class A {
};
#endif
The include guards could also be replaced by #pragma once at the beginning of the header, this is a little less verbose.
Edit
To be complete:
// A.h
#pragma once
#include <vector>
class B;
class A {
std::vector<B*> arr;
public:
void Update(int32 id);
};
// A.cpp
#include "A.h"
// possibly #include "B.h" if necessary
void A::Update(int32 id) {
// impl ...
}
// B.h
#pragma once
class A;
class B
{
int32 id;
A* parent;
public:
void OnRemove();
};
// B.cpp
#include "B.h"
#include "A.h"
void B::OnRemove() {
parent->Update(id);
}
Well, something like this...

the usual way is to provide guarding macros to prevent recursion and move definition of functions in a separate file if needed:
a.h
#ifndef _A_H_
#define _A_H_
#include "B.h"
class A
{
vector<B*> arr;
void Update(int32 id){...};
}
#endif
...
c.cpp (if needed)
#include <a.h>
#include <b.h>
void B::onRemove() {
blahblahblah
}

Related

Circular Includes with inner classes

I'm having an issue wrapping my head around circular include problems and in particular that I'm currently dealing with. I have two classes/structs each in their own files. Class A has an inner class and class B has a member of that type. I need to use instances of B within A which would be ok if they were delcared in the same file but since they're not how can I make this work?
A.h
#pragma once
#include "B.h"
class A
{
public:
class Inner{};
B getNewB() { return B{}; }
};
B.h
#pragma once
#include "A.h"
struct B
{
A::Inner inner;
};
A.h:
#pragma once
#include "innerA.h"
struct B;
class A
{
public:
B getNewB();
friend class InnerA;
};
A.cpp
#include "A.h"
#include "B.h"
B A::getNewB() { return B{}; }
B.h
#pragma once
#include "innerA.h"
struct B
{
InnerA inner;
};
B.cpp
#include "B.h"
InnerA.h
#pragma once
class InnerA
{
};
InnerA.cpp
#include "innerA.h"
I moved A::Inner to another class and add friend relation (You can add bidirectional, use same trick as above I with struct declaration)

Default constructor not called if classes devided into separate files

UPDATE:
Now I have this, and it does not compile:
A.h:
#ifndef A_H
#define A_H
class A {
private:
int foo;
public:
A();
int getfoo();
};
#endif
A.cpp:
#include "A.h"
A::A() {
foo = 5;
}
int A::getfoo(){
return foo;
}
B.h:
#ifndef B_H
#define B_H
class B {
private:
A myA;
public:
B();
int getAvalue();
};
#endif
B.cpp:
#include "A.h"
#include "B.h"
int B::getAvalue(){
return myA.getfoo();
}
Errors:
b.h line 6: C2146: missing ';' before identifier 'myA'
b.h line 6: C4430: missing type specifier - int assumed
b.h line 6: C4430: missing type specifier - int assumed
END UPDATE
I have written 2 classes in different cpp and header files: class A and class B.
Class B uses class A as a private variable and the default constructor of class A is never called.
Here is my code:
A.h:
class A {
public:
A();
int getfoo();
};
A.cpp:
class A {
private:
int foo;
public:
A();
int getfoo();
};
A::A() {
foo = 5;
}
int A::getfoo(){
return foo;
}
B.h:
class B {
public:
int getAvalue();
};
B.cpp:
#include "A.h"
class B {
private:
A myA;
public:
int getAvalue();
};
int B::getAvalue(){
return myA.getfoo();
}
classtest.cpp:
#include "stdafx.h"
#include <iostream>
#include "B.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
B stackB;
cout << stackB.getAvalue() << endl;
B* storeB = new B();
cout << storeB->getAvalue() << endl;
cin.get();
return 0;
}
The output is never 5 and the breakpoint inside the constructor A::A() is never triggered. It doesn't matter if I use B globally or locally. This sample works totally fine if I put the classes and functions in one single file.
If I add an empty default constructor to class B, the default constructor of class A gets called, but then Visual Studio 2008 complains about stack corruption around variable stackB.
What am I doing wrong?
Just with this class alone:
A.h:
class A {
public:
A();
int getfoo();
};
A.cpp:
class A {
private:
int foo;
public:
A();
int getfoo();
};
A::A() {
foo = 5;
}
int A::getfoo() {
return foo;
}
You are declaring class A in A.h.
Then in your implementation(cpp) file, you are then again declaring class A.
You are also forgetting to include A.h in A.cpp. If you included the header into the cpp; the compiler would of thrown out errors telling you what was wrong. You are also missing either header guards, or the pragma directive.
Your class should look like this:
A.h
#ifndef A_H
#define A_H
class A {
private:
int foo;
public:
A();
int getFoo() const; // const to return member and prevents modification
};
#endif // !A_H
A.cpp
#include "A.h" // you forgot to include the header
A::A() : // class constructor using it's member initializer list
foo( 5 ) {
}
int A::getFoo() const {
return foo;
}
Now once you fix your class, then working on class B should not be a problem. However there is one thing to be careful of when including a header file of one class into another; you can end up with circular includes. The best way to prevent that is to use a class prototype in the header and include its header in the containing class's cpp file. There are some cases where a class proto type will not work, but I'll leave that up to you to do the research.
How to use Class Prototype in C++
Class B might look like this:
B.h
#ifndef B_H
#define B_H
// #include "A.h" // uncomment this if prototype below doesn't work.
class A; // class prototype may not work in all cases;
// If the above prototype does not work; comment it out
// and replace it with #include "A.h".
class B {
private:
A myA;
public:
B(); // remove default
int getAValue() const;
};
#endif // !B_H
B.cpp
#include "B.h"
#include "A.h" // If class A's prototype in the header does not work
// then comment this out and place it in this class B's header by
// replacing it with the prototype.
B::B() {} // default constructor (should make this complete type)
int B::getAValue() const {
return myA.getFoo();
}
And this should help to fix your problems. If using the class prototype does not work in the header because in some cases it may not; you can remove the prototype declaration from the header and replace it with the include directive of that class and remove its include from the cpp file.

Implementation File will only recognize forward declaration of other class

I'm having an issue where it appears an implementation file is recognizing only the forward declaration of another class, and not its actual declaration. I've tried using various guards with imports and taking out the forward declaration but to no avail.
Class A has a function "decode" which takes one argument of type B that's defined in a separate file. I'd like to keep all .h's and .cpp's as distinct files. Here they are.
A.h:
class B;
class A{
private:
string sentence;
public:
A();
void decode(const B& decoder);
};
B.h:
class B{
private:
int code[26];
public:
B();
int getCode(int index);
};
A.cpp:
#include "A.h"
A::A(){}
double A::decode(const B& decoder){
B.getCode(1);
//other things
}
B.cpp:
#include "B.h"
B::B(){}
int B::getCode(int index){};
and the driver:
#include "B.h"
#include "A.h"
using namespace std;
int main(int argc, char* argv[]){
B myB;
A myA;
myA.decode(B);
}
I'm compiling this with g++ -Wall driver.cpp B.cpp A.cpp, but get hit with an error that looks like:
A.cpp:4 error: invalid use of incomplete type 'const class B'
I've looked through a ton of similar threads trying to find the answer, but nothing has worked for me yet. Any ideas?
Since you are using B's member function getCode in your A.cpp file, the forward declaration only will not suffice as it says nothing about B's member functions. The entire B declaration needs to be available. To do that, include the "B.h" header in your A.cpp file:
#include "B.h"
As pointed out in the comments you should also utilize the header guards for A.h and B.h headers.
Best practice is that every .h file includes everything it needs. That means A.h shall include B.h.
A.h:
#pragma once // Or equivalent include-guard macros
#include "B.h"
class A{
private:
string sentence;
public:
A();
void decode(const B& decoder);
};
B.h:
#ifndef B_h
#define B_h true
class B{
private:
int code[26];
public:
B();
int getCode(int index);
};
#endif
A.cpp:
#include "A.h"
A::A(){}
double A::decode(const B& decoder){
B.getCode(1);
//other things
}
B.cpp:
#include "B.h"
B::B(){}
int B::getCode(int index){};
and the driver:
#include "A.h"
void main(){
B myB;
A myA;
myA.decode(B);
}

Cyclic dependency in Eclipse CDT

I know this matter doesn't get enough attention because it's not meet often but I want to clarify it.
Say I have 3 files:
A.h
#ifndef A_h
#define A_h
#include "B.h"
class A {
A();
virtual ~A();
bool someFunc(B& b);
};
#endif
B.h
#ifndef B_h
#define B_h
#include "A.h"
class B {
B();
virtual ~B();
bool someFunc(A& a);
};
#endif
and main.cpp
#include "A.h"
#include "B.h"
int main() { return 0; }
without the protection (#ifndef X_h #define X_h) there is a Cyclic dependency. Adding the protection should solve the problem but when the code is compiled first main.cpp tries to include a.h which tries to include b.h before a is declared and that returns an error. If we change the code to:
A.h
#ifndef A_h
#define A_h
class A {
A();
virtual ~A();
#include "B.h"
bool someFunc(B& b);
};
#endif
B.h
#ifndef B_h
#define B_h
class B {
B();
virtual ~B();
#include "A.h"
bool someFunc(A& a);
};
#endif
Now the Cyclic dependency is solved but and the code compiles without error but still Eclipse returns an error: "Type 'B' could not be resolved" in A.h so you need to add surpress to both A.h and B.h where the other one is used. I want to know if there is another way to solve the Cyclic dependency without Eclipse returning an error and how should the code look if we have more than two classes (A includes B, C and D; B includes A, C, D ...)
As long as you don't actually use instance of class B in class A and the other way around, and only declare functions taking pointers or references, you can get away without including at all, and only declare the classes:
In file A.h
#ifndef A_h
#define A_h
class B; // Declare class B
class A {
A();
virtual ~A();
bool someFunc(B& b);
};
#endif
and in B.h
#ifndef B_h
#define B_h
class A; //Declare class A
class B {
B();
virtual ~B();
bool someFunc(A& a);
};
#endif
In the source files where the functions are defined (implemented) you of course needs to include both files.

C++ Forward Declaration and Inheritence

I have a situation as such
A.h
#ifndef _CLASSA
#define _CLASSA
class B;
class A {
virtual void addTo(B*) {}
};
#endif
B.h
#ifndef _CLASSB
#define _CLASSB
#include "A.h"
class B : public A {
B();
void addTo(B* b) {
// blah blah blah
}
};
#endif
B.cpp
#include "B.h"
B::B() : A() {}
main.cpp
#include "B.h"
int main() {
A* b = new B();
B* d = new B();
b->addTo(d);
}
The project won't compile. If I forward declare B in the A header, the compiler complains about the expectation of a class in B.h. If I include the B.h header in A.h, the compiler can't resolve the base class. Is this possible?
Yes, include A.h in B.h and forward declare B in A.h.
If I forward declare B in the A header, the compiler complains about the expectation of a class in B.h
The way you have the code now it should work. But I suspect you're actually using B inside the method addTo, in which case a forward declaration is not enough. You need to separate the implementation to an implementation file and include B there.
EDIT: As DeadMg pointed out, class B : class A { isn't valid syntax, you probably want class B : A or class B : public A.