5

I have some class Foo and Logger:

class Logger{/* something goes here */};
class Foo{
  Foo(Logger& logger);
  Logger& logger;
}

Foo::Foo(Logger& logger) : logger(logger)
{}

Now I want to create an array of objects of class Foo, where all references Foo::logger should point to the same Logger object. I tried something like (I need both stack and heap allocation):

Logger log (/* parameters */);
Foo objects [3] (log); // On stack
Foo* pObjects = new Foo [3] (log); // On heap

The problem is that both versions try to call the default constructor Foo() which is not present. Also as I understand it is not possible to change the referenced variable of a reference. So a temporary call to the default constructor and a later initalisation in a loop does also not help.

So: What is the right way to do it? Do I need to use pointers to the Logger object?

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
Christian Wolf
  • 1,187
  • 1
  • 12
  • 33

3 Answers3

5

You cannot initialize an array of objects with non-default constructor. However you can use a vector as shown here (Look at the first reply)

And for the heap you can do the following :

Foo* pObjects[3];

for (int i = 0; i < 3; ++i) {
   pObjects[i] = new Foo(log);
}
giorashc
  • 13,691
  • 3
  • 35
  • 71
2

You can initialize an array of objecs with the non-default constructor using the C++11 brace initialization:

class Logger{/* something goes here */};
class Foo{
public:
  Foo(Logger& logger);
private:
  Logger& logger;
};

Foo::Foo(Logger& logger) : logger(logger)
{}


EDIT: In C++11, you can use vector to do what you want:
#include <vector>
class Logger{/* something goes here */};
class Foo{
public:
  Foo(Logger& logger) : logger(logger) {}
private:
  Logger& logger;
};

int main () {
  Logger log;
  std::vector<Foo>(3, log);
}

Note that the vector solution won't work in C++03. In C++03 that vector constructor invokes Foo::operator=. In C++11 it invokes Foo::Foo(const Foo&).

Robᵩ
  • 163,533
  • 20
  • 239
  • 308
  • That only works if I know the number of elements a priori, right? This is not always true for my problem. – Christian Wolf Apr 04 '12 at 14:02
  • True, that is a problem. But realize that you must know the number of elements *a priori* when you create arrays on the stack. – Robᵩ Apr 04 '12 at 14:06
2

For general uses I normally make a logger a Singleton so there is only one and can be accessed from all components. http://en.wikipedia.org/wiki/Singleton_pattern

This also makes the constructor of Foo much simpler.

class Logger
{
    public:
        static Logger& getInstance()
        {
            static Logger    instance;
            return instance;
        }

        public log(const std::string& txt) 
        {
            //do something
        }

    private:
        Logger() {}
        Logger(Logger const&);              // Don't Implement.
        void operator=(Logger const&); // Don't implement
 };

And use it in Foo like:

 Logger::getInstance().log("test");

or

 Logger& logger = Logger::getInstance();
 logger.log("test");

(Credits for singleton from @Loki Astari : C++ Singleton design pattern )

Community
  • 1
  • 1
RvdK
  • 19,580
  • 4
  • 64
  • 107
  • To be sure that I understand you: You mean some static member for all objects? How to initialize it then? Or a separate object/global variable/...? – Christian Wolf Apr 04 '12 at 14:11
  • He means a singleton class which is accessible from everywhere in your code. This is the common way for loggers. – giorashc Apr 04 '12 at 14:33