1

I'm making a small game in the console and have come across a small problem. Let's say I have a class named Canvas:

canvas.h

class Canvas final {

public:
  // Constructor
  Canvas(unsigned width = 10, unsigned height = 30);

  unsigned outerWidth, outerHeight;

}

canvas.cpp

#include "canvas.h"

Canvas::Canvas(unsigned width, unsigned height) {
  outerWidth = width;
  outerHeight = height;

  // I draw a box (canvas)'s border here
}

Now in the main.cpp file I declare an instance of the class:

#include "canvas.h"

// The program starts here
int main() {
  Canvas myCanvas;
  return 0;
}

First of all, I would like to only have 1 member of the Canvas class, because that's how my program is designed to be. However, when I make an instance of that class, it gets a name (myCanvas in this example). Then if I want another class (let's say, Entity) that uses the canvas, I have to say myCanvas.outerWidth, which is dependent on the object's name. Also, I don't think the myCanvas variable would be available in the scope of such class anyway.

On the other hand, when I use namespaces, I lose some benefits of using classes (encapsulation (private properties), constructors). So what do I do? Make a static class or namespace or what? I've heard that there isn't a thing called a static class in C++; there are only static properties or methods. I guess putting the static keyword everywhere isn't good practice. Or is it?

Volper
  • 644
  • 6
  • 14
  • 2
    Create a header file, don't use `class`, use a `namespace` and in addition use an anonymous namespace to make things that you want to be `private` have internal linkage. – Fureeish Sep 15 '19 at 13:12
  • If you need only one instance of a `class`, you can use [singleton design pattern](https://stackoverflow.com/questions/270947/can-any-one-provide-me-a-sample-of-singleton-in-c/271104#271104). – mrazimi Sep 15 '19 at 13:25
  • When you want to use `myCanvas` object in scopes other than `main` you should pass a reference to this object there. There is no need to pop global or static member variables all of it sudden. – user7860670 Sep 15 '19 at 13:29
  • @VTT Yeah but I don't like passing a variable to every function I use with the canvas – Volper Sep 15 '19 at 13:31
  • 2
    @mrazimi consider some examples of using `static` methods from singleton class implenentation. Do they remind you of something? Yes, the syntax is **exactly the same** as one used when you use namespaces rather than classes. Thus I believe one should not use singleton classes at all in C++, but rather use namespaces if the singleton-like behaviour is desired. – Fureeish Sep 15 '19 at 13:44
  • 2
    @Fureeish No, syntax is not the same. In-class declarations allow different access control levels. Also singleton is still a singleton regardless of whether it employs free functions or member functions of some class. – user7860670 Sep 15 '19 at 14:27
  • 1
    @VTT I should've specified that I was referring to calling syntax. And they are the same, essentially. – Fureeish Sep 15 '19 at 14:39
  • 1
    Yeah but how do I make a readonly variable inside a namespace (read access outside of file, read & write access inside file)? I need to make a constant `width` variable that can be only inititialized once. I don't see any simple way to do that using namespaces. – Volper Sep 15 '19 at 14:47

1 Answers1

1

If you want to have a single instance (i guess you want a single instance, not a single member, as a member is one of the component fields of the class, and as such, your class has two member fields now) you are probably talking about the singleton pattern (a class with only one instance and no means to instantiate another).

Just declare the constructor private or protected, so client code cannot make a second instance of that object. In that case, you can only use instances already generated for client code, and client code cannot get a new instance (by means of new operator or declaring an instance in main() as you do).

class Canvas final {

  // Constructor now is private
  Canvas(unsigned width = 10, unsigned height = 30);

public:
  unsigned outerWidth, outerHeight;

}

I'd recommend you also to declare outerWidth and outerHeight as const if they are to be exposed publicly by the class, so you cannot modify them (making the instance immutable) or declare accessor methods to access those fields and declare a public and static field instance (or theCanvas), as in:

class Canvas final {

  // Constructor
  Canvas(unsigned width = 10, unsigned height = 30);

public:
  unsigned outerWidth, outerHeight;
  static Canvas instance;  // we have a static instance defined elsewhere

}

you can instantiate it in a .cc file with:

#include <canvas.h>
...
Canvas Canvas::instance;  // by default 10 by 10, this is the public available instance declared above.
...

in this way, you can use Canvas::instance everywhere, that will be an instance of your Canvas class. It will be visible from any source that includes the "canvas.h" include file, and not only in your main() routine, as it is in the sample snippet you post.

By the way, there's no much sense in declaring a constructor with parameters if you are only using it once and in your private code. Also no need to declare default parameter values, but you are in your way. You decide.

Note

As it is not fully clear what you are attempting, I could have misunderstood your intentions, so please, don't blame me if this is not what you want, and edit your question to make your target clearer. You have declared outerWidth and outerHeight as non-const and so, they are modifiable by any code that has access to them. It's not clear if you want your instance immutable (not modifiable once it has been instantiated) nor if they have to take their values from some external code.

Community
  • 1
  • 1
Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
  • About the outerWidth and outerHeight variables, I want them to be constant but declared later (when drawing the canvas in the constructor). Is there a way to do that? Also, about the constructor, in the main function I would like to specify the width and height and then copy them in a class method to the outerWidth and outerHeight variables. Basically I want all (or most) of the Canvas properties not modifiable from the outside but defined in the Canvas::draw() function as constants or something – Volper Sep 16 '19 at 10:30
  • I haven't tested this, but I think it's gonna work. I'll mark this answer correct anyway – Volper Sep 20 '19 at 13:56
  • 1
    I'm sorry, but as you posted only partial code, it has been impossible for me to supply the missing code, without also incurring in misinterpreting your intentions... next time post a complete and verifiable example, and so the answer will be. – Luis Colorado Sep 20 '19 at 17:50