Search code examples
c++classoopnamespacesencapsulation

Namespace or class with one member?


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?


Solution

  • 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.