0

I am spitting through some old C++ code. In it, I declare a local variable like this:

Pen blackPen(Color(255, 0, 0, 0));

This seems to call the constructor.

I am trying to make this a global variable, which I want to initialize in a function. However, I am not able to split the variable from it's initialization in this way. Of course, I can define a global variable

Pen blackPen;

But now I don't know how to initialize it:

blackPen = Pen(Color(255, 0, 0, 0));

seems the most reasonable, but I get an error:

"Gdiplus::Pen::Pen(const Gdiplus::Pen &)" (declared at line 452 of "c:\Program Files (x86)\Windows Kits\8.1\Include\um\gdipluspen.h") is inaccessible

The following snippet shows this behavior:

#include <windows.h>
#include <gdiplus.h>
using namespace Gdiplus;

Pen redPen;

int main(int argc, char *argv[])
{
    Pen greenPen(Color(255, 0, 0, 0)); // this initialization works
    redPen = Pen(Color(255, 0, 0, 0)); // but this doesn't...
    return 0;
}
Ruben
  • 180
  • 1
  • 11
  • 1
    It seems your copy constructor is private. Can you post an [MCVE](http://stackoverflow.com/help/mcve)? – Emil Laine Feb 17 '17 at 20:00
  • Looks like you can't. The error is saying the copy constructor is private. It might be moveable, do you have C++11 turned on? – NathanOliver Feb 17 '17 at 20:01
  • Provide a [MCVE] please. – πάντα ῥεῖ Feb 17 '17 at 20:01
  • I was under the impression that this was a beginners mistake and that a MCVE was not needed. I will update the question. – Ruben Feb 17 '17 at 20:03
  • Just a FYI, if you can make a MCVE then providing one will almost never hurt. A little extra information is a lot better then not enough information. – NathanOliver Feb 17 '17 at 20:05
  • 1
    `Pen blackPen;` already shoudln't compile; `Gdiplus::Pen` class doesn't have a default constructor. You have to initialize `Pen` object at the point of creation. Why do you feel the need to initialize it separately? You can happily have `Pen blackPen(Color(255, 0, 0, 0));` as a global variable. – Igor Tandetnik Feb 17 '17 at 20:09
  • @IgorTandetnik Thank you, that is useful information. I have a background in C, and I am not familiar with this concept. Curiously, VS doesn't complain at that line. It seems I have to initialize the pen after calling GdiplusStartup, so it doesn't work if I initialize it this way. – Ruben Feb 17 '17 at 20:16
  • Your `redPen = ...` line has nothing to do with initialisation. It's an assignment (or an attempt to perform an assignment). The fundamental difference between initialisation and assignment is largely the same in C++ as in C. – Christian Hackl Feb 17 '17 at 20:18
  • @ChristianHackl If you write "int i; i = 0;" I would refer to the assignment as an initialization, I'm not sure if this is right, but more people seem to use this convention of referring to the first assignment as the initialization, even if its not done in the same line as the definition of the variable. See for example http://stackoverflow.com/a/2614422/5697092 – Ruben Feb 17 '17 at 20:40
  • 1
    For classes, the distinction matters. `C c = 0;` would use `C::C(int)` constructor, while `C c; c = 0;` would use `C::C()` default constructor followed by `C::operator=(int)` assignment operator. The class may provide some, none or all of those, so it's possible that one example compiles and the other doesn't. In particular, `Gdiplus::Pen` provides a constructor from `Color`, but not a default constructor nor an assignment operator. – Igor Tandetnik Feb 17 '17 at 20:50
  • 1
    @Ruben: Your link refers to Java, not C++! Java has very different rules regarding initialisation than C++. The distinction is best illustrated with `final` and `const`. You can indeed do something like `final int i; /* ... */ i = 123;` in Java, but `int const i;` is a compilation error in C++. C++ has very clear rules about initialisation and assignment; there is no room for interpretations or conventions. See http://en.cppreference.com/w/cpp/language/initialization – Christian Hackl Feb 18 '17 at 11:09
  • @ChristianHackl In that case you're absolutely right. I wasn't aware that there was such a definition. – Ruben Feb 18 '17 at 16:14

2 Answers2

4

I am trying to make this a global variable, which I want to initialize in a function. However, I am not able to split the variable from it's initialization in this way.

One option is to provide access to the variable through a function.

Pen& getBlackPen()
{
   static Pen pen{Color{255, 0, 0, 0}};
   return pen;
}

Then, you will have access to object anywhere the function declaration is available. It will be initialized when the function is called the first time.

Update, in response to OP's comment

Another option (provided Pen meets the requirements of being the value type of std::map):

Pen& getPen(std::string const& name)
{
   static std::map<std::string, Pen> pens =
   {
      {"black", Pen{Color{255, 0, 0, 0}} },
      {"white", Pen{Color{...}} },
      {"red", Pen{Color{...}} },
      // etc.
     };
   }

   return pens[name];
}

Now, you can use:

Pen& pen1 = getPen("black");
Pen& pen2 = getPen("red");
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • This works (so you have my upvote), but I don't find it elegant: I don't want to define a function for every Pen. I am waiting if a more elegant solution pops up (else I'll accept your answer). – Ruben Feb 17 '17 at 20:30
  • Update: When calling GdiShutdown, this will try to destroy the Pen, and this will lead to an access violation error. So it doesn't fully work as intended. – Ruben Feb 17 '17 at 20:51
  • 1
    @Ruben, you are raising valid points but I they are beyond what your original post raised as an issue. I hope you can take ideas from the answer and adapt them to solve all other issues that you are seeing in your program. – R Sahu Feb 17 '17 at 21:12
  • @R Sahu You're right. The crashing had to do with other mistakes I made. I don't really like C++ to say the least. – Ruben Feb 17 '17 at 21:45
  • @Ruben, it's a spiderman thing :) With great power comes great responsibility. – R Sahu Feb 17 '17 at 21:50
0

My solution was to define a pointer instead of a Pen directly, and then use the constructor that works from a brush:

#include <Windows.h>
#include <gdiplus.h>
using namespace Gdiplus;

Brush *blackBrush;
Pen *blackPen;

int main(int argc, char *argv[])
{
    blackBrush = new SolidBrush(Color(0, 0, 0));
    blackPen = new Pen(blackBrush);
    return 0;
}
Ruben
  • 180
  • 1
  • 11