nass
nass

Reputation: 1485

mixing c++ class inheritance and initializer lists. An unsolved puzzle in my mind

I have 4 classes

class A { //a base class
    public:
    A(ostringstream* os){ oss2=os; }
    ostringstream* oss2;
};

class B : public A{ // a derived class 
    public:
    B(ostringstream* os):A(os){};
};

class C { //class where oss is actually declared
    public:
    C(){};
    ostringstream oss;
};

and finally (the kicker): a derived class from "C" , that needs to pass a reference to oss around.

class D : public C{
    public:
    B b(&oss);
};

in line B b(&oss); I get the error

error: expected identifier before ‘&’ token

I honestly don't know if I am playing with fire here. The basic idea is that I want some functions of A to write to a common output stream.

This is not a logging class but I see that some loggers declare a static oss variable and allow everyone to write there. I would prefer to avoid that and instantiate my oss in the (logically) correct location. In my case, that is in class C.

I think (but I could be wrong) that the error here is that I am trying to provide a reference to a variable (oss) through the declaration of B b. Is that right? Instead an initializer list should be used to provide the value to the constructor. But I am not sure how to implement this (and test if it compiles).

Upvotes: 0

Views: 86

Answers (2)

CompuChip
CompuChip

Reputation: 9232

If you want to have a field of type B in D, you should just declare it there and initialize it in the constructor, as you already hinted at:

class D : public C{
  public:
    D() : 
      C(),    // You can leave this out, the compiler will do it for you
      b(&oss) // Once the C part is constructed you can pass in its field.
    {}

  private: // ?
    B b;
};

But depending on your situation, there may be a better solution in terms of design. For example, if C is a base class for output, and A is a class that needs to do some logging, you could go with a solution like this:

class A { // worker base class
    public:
        A(C* logger) : logger(logger) {}
    private:
        C* logger;
};

class B : public A{ // a derived class 
    public:
        B(C* logger) : A(logger) {};
};

class C { // logging class
    public:
        C(){};  
        virtual ~C() {};
        virtual void Log(const std::string& message) = 0;
};

class D : public C { // a derived class
  public:
      D() {} 
      virtual void Log(const std::string& message) 
      {
        this->oss << message;
      }
  private:
      ostringstream oss;
}

// In main:
D streamLogger;
A worker(&streamLogger);

Now A doesn't care what it outputs to, just pass it a class which supports Logging a message and let polymorphism handle the rest. In fact, if you want to have a logging method that sends emails, just create a new derivative of C and pass it into the same A instance.

Upvotes: 2

James Adkison
James Adkison

Reputation: 9602

You need to properly declare a B data member and then construct is properly.

class D : public C
{
public:
    B b; // Declare a 'B' type

    // 'B' must be instantiated with a single argument therefore it must be
    // constructed in the initializer list
    D() : b(&oss) {}
};

Upvotes: 2

Related Questions