0

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?

TrapClap
  • 3
  • 2
  • 1
    Why do you declare two different classes with the same name in the header _and_ the source file? – Arnav Borborah Mar 15 '18 at 10:41
  • Otherwise it won't compile. Should I remove it from the header or source file? – TrapClap Mar 15 '18 at 10:42
  • 1
    You have two class declaration for both A and B. Remove declarations from .cpp files (they don't belong there) and make sure delarations in .h files also have member fields. Also add #include "A.h" in A.cpp and likewise in B.cpp (so the compiler can see the actual declarations). – Yksisarvinen Mar 15 '18 at 10:42
  • You are re-declaring the classes in your `.cpp` file. Just remove that and put the full defenition in the `.hpp` and things should be ok. – super Mar 15 '18 at 10:42
  • Oh, and your `A.cpp` file needs to `#include "A.h"`. – super Mar 15 '18 at 10:44
  • There is a real problem with the includes in your code. Just include B.h from B.cpp, A.h from A.cpp and B. cpp, B.h from main.cpp, that should help. And protect all your .h with ifndef macros. – Benjamin Barrois Mar 15 '18 at 10:55
  • 1
    If you are learning C++, please don't use VS2008. You are pretty obviously missing out on the C++11, C++14, and C++17 revisions of the language. The differences are huge. – Bo Persson Mar 15 '18 at 11:34
  • @BoPersson yeah already mentioned that to the OP. – Francis Cugler Mar 15 '18 at 11:34
  • @BoPersson Yeah, but VS2008 is what we have here at work... – TrapClap Mar 15 '18 at 14:22
  • @FrancisCugler Yeah, but VS2008 is what we have here at work... – TrapClap Mar 15 '18 at 14:23
  • @TrapClap Oh I see; well you should bring it up at a staff meeting... Time to update some components. – Francis Cugler Mar 15 '18 at 15:03
  • @FrancisCugler Sadly, this is not possible, because we use Windows CE 6 on our handhelds and VS2008 is the latest version supporting this OS. The new revision of our devices is based on Yocto Linux, though. – TrapClap Mar 15 '18 at 15:40

1 Answers1

0

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.

Francis Cugler
  • 7,788
  • 2
  • 28
  • 59
  • It doesn't compile: C2079: 'B::myA' uses undefined class 'A'; C2065: 'default': undeclared identifier; C2253: pure specifier or abstract override specifier only allowed on virtual function and so on – TrapClap Mar 15 '18 at 11:15
  • @TrapClap Prototypes are tricky for classes, there are cases it won't work and cases it will. Read the comments. If the prototype doesn't work, replace it with the include. You are declaring an object of A in B so I think that it may not. If you were declaring a pointer of A in B, then it should. But it has to be a complete type. – Francis Cugler Mar 15 '18 at 11:17
  • If I replace 'B()=default;' with 'B();' some errors go away. If I replace the class prototype with an include I get a new error: LNK2019: unresolved external symbol "public: __thiscall B::B(void)" (??0B@@QAE@XZ) referenced in function _wmain – TrapClap Mar 15 '18 at 11:21
  • @TrapClap if you replace the prototype with the header include. You will then also have to supply a constructor for B so that it is a complete type. Also you can not have A depend on B while B depends on A. This will also result in infinite recursion. – Francis Cugler Mar 15 '18 at 11:22
  • ist this 'default' thing C++11? If yes, VS2008 does not support it. – TrapClap Mar 15 '18 at 11:25
  • @TrapClap That I'm not sure of. I don't actually know when they added in the `= default` for constructors, destructors and =operator. – Francis Cugler Mar 15 '18 at 11:26
  • @TrapClap If you are able to you should be able to download Visual Studio 2017 CE (Community Edition) for free. Then that way you can set the `c++ language flag` for the compiler to use c++11, c++14 and many parts of c++17. – Francis Cugler Mar 15 '18 at 11:27
  • This is my first adventure in C++ and it's very very very complicated. Normally I develop very small tools in C# to simplify my everyday work. I know I am not that good at it, but it was sufficient until today. – TrapClap Mar 15 '18 at 11:28
  • @TrapClap C++ is a beast to tackle but well worth it in the end. – Francis Cugler Mar 15 '18 at 11:29
  • @TrapClap I've been self taught in C++ for about 10 - 15 years now; and I've learned how to use OpenGL & DirectX to create working 3D Graphics - Game Engines. And I'm still learning! – Francis Cugler Mar 15 '18 at 11:30