0

I'm in trouble with my c++ code

I've got two classes:

Console and Logger

the only problem is that constructors should look like:

Console(Logger * L): L(L) // Copy pointer
Logger(Console * C): C(C)

and my whole program should look like

Console C(&L); // BUT L IS NOT DEFINED YET
Logger L(&C);

int main()
{

}

How can i solve that?

peku33
  • 3,628
  • 3
  • 26
  • 44
  • 2
    possible duplicate of [When can I use a forward declaration?](http://stackoverflow.com/questions/553682/when-can-i-use-a-forward-declaration) – πάντα ῥεῖ Jul 15 '14 at 21:27
  • @πάνταῥεῖ I disagree, this question is about initialization order, not class declaration order. – Stian Svedenborg Jul 15 '14 at 21:33
  • @StianV.Svedenborg _'this question is about initialization order'_ Where did you get this from actually? – πάντα ῥεῖ Jul 15 '14 at 21:35
  • The question states "L is not defined yet", not "Logger is not defined yet." – Stian Svedenborg Jul 15 '14 at 21:41
  • @πάνταῥεῖ: That's part of the answer. At least it would be if it was about those types, and not about specific objects of those types. – Deduplicator Jul 15 '14 at 21:42
  • @StianV.Svedenborg The OP is missing to clarify a number of points actually! Everything else is just speculative ... – πάντα ῥεῖ Jul 15 '14 at 21:43
  • @Deduplicator Maybe :-/ ... – πάντα ῥεῖ Jul 15 '14 at 21:44
  • 1
    @πάνταῥεῖ Despite first appearances, forward declaration isn't sufficient here. – Neil Kirk Jul 15 '14 at 21:44
  • @NeilKirk: It certainly looks to me like a forward declaration of one class, _and_ a forward declaration of a variable would solve this problem, as long as certain assumptions about the constructors are made. – Mooing Duck Jul 15 '14 at 22:15
  • Even if you actually solve this problem, it seems like bad design to me. What happens if Console tries to log an error before the Logger is finished being constructed, or vice versa? (Not to mention all the other problems associated with static initialization). It would be better to have a defined order, e.g. Logger first, then Console; and things which might need to use Console take some other action if Console is not yet created. – M.M Jul 15 '14 at 22:23
  • @MooingDuck There's no such thing as forward declaration of a variable. – Neil Kirk Jul 15 '14 at 22:48
  • @NeilKirk: §7/6 "...An object declaration, however, is also a definition unless it contains the extern specifier and has no initializer..." – Mooing Duck Jul 15 '14 at 22:57
  • @MooingDuck How can this problem be solved using the extern specifer? – Neil Kirk Jul 15 '14 at 23:01
  • @NeilKirk: As I said, forward declare the class and a variable: http://coliru.stacked-crooked.com/a/79b5b97413f2f2b7 – Mooing Duck Jul 15 '14 at 23:04
  • @MooingDuck So all loggers have to be global and the number fixed at compile time? That's not a good solution. – Neil Kirk Jul 15 '14 at 23:06
  • @NeilKirk: Or they can be on the stack. Or in boost::optionals. Or in a vector if you're crafty and careful. (I'm not validating or encouraging his design, merely saying it's possible) – Mooing Duck Jul 15 '14 at 23:09
  • @MooingDuck But you can't extern on the stack or in a vector. I don't understand what you are saying. – Neil Kirk Jul 15 '14 at 23:09
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/57354/discussion-between-mooing-duck-and-neil-kirk). – Mooing Duck Jul 15 '14 at 23:13

7 Answers7

3

The answer is, it depends.

Do both objects require the other being up and running?
You are SOL, they cannot both be constructed last. Reconsider your design. Maybe you can get basic service set up without referring to the other object for one of them, think multi-stage init.

Do both only need to save that reference for later use?
The order does not matter, use a forward declaration for at least one of them. You might even define them in separate compilation units.

Does exactly one of them potentially use the other in its ctor / dtor (including indirectly)?
Define that object later in the same compilation unit and you are ok.

extern Type name; // This is a forward declaration, like in headers
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
1

You'll have to move one of them outside of its constructor and pass it in after creation:

Console C;
Logger L(&C);
C.set(&L);
Bert Goethals
  • 7,867
  • 2
  • 20
  • 32
Lochemage
  • 3,974
  • 11
  • 11
  • C is a class, and creating one using C() is perfectly valid and illustrates the point that I am creating an instance using its default constructor passing in nothing. Console C; and Console C(); both perform the same operation. – Lochemage Jul 15 '14 at 22:10
  • 1
    No, wrong. You have a function declaration. Try it out and see. OK, now somebody else fixed it for you. – juanchopanza Jul 15 '14 at 22:11
0
Console(){} 
Logger(Console * C): C(C) {C->L=this;}

Console C();
Logger L(&C);
dari
  • 2,255
  • 14
  • 21
0

Unfortunately no, what I suggest is that you move the the "binding" of them to a separate function.

For this particular use case I recommend creating a bindLogger method in both classes:

void Console::bindLogger( Logger * logger ) {
     if (logger != L) {
         L = logger;
         logger->bindConsole( this );
     }
}
Stian Svedenborg
  • 1,797
  • 11
  • 27
0

The only solution I can think of, which might not be good design, is:

class Logger;
class Console;

class Console
{
public:
    Console(Logger *l) : l(l) {}

private:
    Logger *l;
};

class Logger
{
public:
    Logger(Console *c) : c(c) {}

private:
    Console *c;
};

class Together
{
public:
    Together()
        : c(&l)
        , l(&c)
    {
    }

private:
    Console c;
    Logger l;
};
Neil Kirk
  • 21,327
  • 9
  • 53
  • 91
  • 1
    That might work, as long as the constructor of one is not actually using the other. (If the constructor of Console is logging for instance). You could also do something similar without the extra class if you use placement new, and some rather dirty casts. – Stian Svedenborg Jul 15 '14 at 22:04
-1

You'll have to dynamically create one of the two objects to avoid issues with initialization order.

Timo Geusch
  • 24,095
  • 5
  • 52
  • 70
-1

With such constructors as you require this is not possible. You have to allow one of the objects to have default constructor and set the pointer later.

Wojtek Surowka
  • 20,535
  • 4
  • 44
  • 51