2

I have two classes (actually four, but they're not required for this). Let's call them A, and B. I am trying to declare class B as a member in class A. My problem is, I need access to a member function inside of class A from class B, but it doesn't make sense for these two classes to be inherited from each other.

Here are the two classes:

Class A:

#include "B.h"

class A {
    B test;
public:
    A() : test {this} {}

};

Class B:

#include "A.h"


class B: public Alert {
    A* test;
public:
    B() = default;
    B(A* testIn) : test{ testIn } {}

        // member functions
};

I am using Visual Studio Community Edition 2022 (64-Bit). My C++ version is C++11.

The compiler error I keep getting is "testIn undeclared identifier." This makes no sense to me, as I feel I have declared it.

I understand that making one of the classes a child of the other would allow the child class to access the public and protected members of the parent class.

The thing is, in this instance, it makes no sense for them to inherit from each other. I only need access to a function inside of class A from class B, as class A inherits from another class. I am trying to write a library, and want class A to be the class that would be used by other people. It wouldn't make any sense having class B be the class to be used in the final program. Which is why I didn't want to inherit the one from the other.

I appreciate your time for looking at my question.


Update: John's solution posted below in his own submission is correct for my original question. I am just an idiot and forgot to include that Class A also inherits from another class.

Class A would look like the following:

#include "AnotherClass.h"
#include "B.h"

class A: AnotherClass {
    B test;
public:
    A() : test {this} {}

};

Terribly sorry about my confusion. I definitely messed up.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • I am unable to reproduce this issue, https://godbolt.org/z/bEdKcxdET Are you able to provide more information? – Substitute Dec 24 '22 at 07:08
  • 4
    You have a circular inclusion. B must not include A, it should forward-declare it. – HolyBlackCat Dec 24 '22 at 07:09
  • Is `B` always constructed as a part of `A`? If yes, you might be able to pull off some hackery to avoid storing the unnecessary pointer. – HolyBlackCat Dec 24 '22 at 07:10
  • @Substitute, I have posted a comment in John's answer to my problem. I can update the code in my question if you'd like. I believe that would help you to get the same error. – ConfusedCoder Dec 24 '22 at 07:23
  • @HolyBlackCat, yes, class B would always be constructed as part of class A. The default constructor is just for testing at this point. – ConfusedCoder Dec 24 '22 at 07:24
  • Then why is a separate class needed in the first place? Just plop all the members directly into A? – HolyBlackCat Dec 24 '22 at 07:25
  • @HolyBlackCat, Class B only need to access a single member function inside of Class A, but the two classes do entirely separate tasks. It made no sense to me to rewrite the same member function in Class B to do the same task, but for a completely different outcome. I hope that makes sense. What you wrote makes perfect sense, but in my use-case, it does not. – ConfusedCoder Dec 24 '22 at 07:39
  • What do those classes do? Maybe we'll be able to suggest a better design. – HolyBlackCat Dec 24 '22 at 07:45
  • One time I needed to do this, I used `offsetof` to get a pointer to `A` from `B` to avoid storing it. But the only reason I had to have two separate classes is because of some macro hackery. – HolyBlackCat Dec 24 '22 at 07:48
  • @HolyBlackCat, John's solution is correct, so I have marked it as so. Perhaps a better design could be implemented, but for now, I am very happy with this solution. I appreciate your help as well! – ConfusedCoder Dec 24 '22 at 07:58
  • Ok, you're welcome! Please don't add "solved" to the title, awarding an answer with a checkmark already marks the question as solved. – HolyBlackCat Dec 24 '22 at 08:08
  • Apologies, I'll change that. I thought that was the correct thing to do. Thank you for being patient with me. ;) – ConfusedCoder Dec 24 '22 at 08:09

1 Answers1

6

You have a cyclic include problem, "A.h" is including "B.h" which again includes "A.h". Think about it (carefully), "A.h" immediately includes "B.h" which again immediately includes "A.h" but this time "A.h" is skipped (because it has been previously included, even though not fully processed yet) which means that you are processing class B without having yet seen a declaration for class A.

Here's how you might break the cycle.

"A.h" is as before

#include "B.h"

class AnotherClass
{
};

class A : AnotherClass {
    B test;
public:
    A() : test {this} {}
    void something();
};

But "B.h" uses a forward declaration to break the cycle

class A; // forward declaration

class B: public Alert {
    A* test;
public:
    B() = default;
    B(A* testIn) : test{ testIn } {}
    void member_function();
};

A forward declaration is fine for test and testIn as long as you do not try to use those pointers.

Now in "B.cpp" you can call A methods.

#include "B.h"
#include "A.h"

void B::member_function()
{
    ...
    test->something();
    ...
}
john
  • 85,011
  • 4
  • 57
  • 81
  • This is the correct answer. I think I messed up with asking the question correctly, though. So, I'm not sure if I should mark this as correct or not. I edited the original names of my classes, and meant to remove the classes that they inherited from in the question. In my actual code, Class A also inherits from another class. I believe there is no way to forward declare a class like that. So, your solution is correct, but I'm not sure if I mark this as solved and post another question with my updated code, or edit this question with my actual code. Your answer is certainly correct, though. – ConfusedCoder Dec 24 '22 at 07:21
  • You are correct you cannot forward declare a class you are inheriting from. But a class that inherits from another class can be forward declared, so I don't see what difference it would make to the solution presented here. – john Dec 24 '22 at 07:25
  • I updated my original post, so I hope you can see what I mean. I understand what you are saying, and that is correct. If you'd be kind enough to read my update, I hope what I'm trying to say makes more sense. Apologies if I just seem even more confused, as I probably am. I'll mark your answer as correct if your solution still stands. ;) – ConfusedCoder Dec 24 '22 at 07:31
  • @ConfusedCoder I updated my answer. I think it still stands. I can't really see any problems but I suppose the issue might be where is `AnotherClass` defined? – john Dec 24 '22 at 07:42
  • I will try your updated solution now. To answer your question, I have ``AnotherClass`` declared in a separate header file. I have edited my question to show this now. Apologies for more mistakes on my behalf. – ConfusedCoder Dec 24 '22 at 07:46
  • After testing your code, I realized I also needed to declared a member function in class B to be a friend of class A. Your solution works. Thank you very much. This is the correct answer, and I have marked it as so. I appreciate your time! – ConfusedCoder Dec 24 '22 at 07:56
  • @ConfusedCoder No problem, glad to help. The first time you write headers with cyclic includes it is baffling, as the compiler error messages don't make much sense. – john Dec 24 '22 at 08:02
  • That was my exact issue. The compiler errors made no sense to me, as in my head, it all made sense. I knew about forward declarations for functions, but not about classes. I never thought about cyclic includes, as I had "#pragma once" in all my headers, so thought it wouldn't be possible for them to constantly be included. Now that I think about it, this all makes sense. Glad to learn from this, it'll definitely help me in the future. Your help is greatly appreciated. – ConfusedCoder Dec 24 '22 at 08:08