I have simple question about class design in C++.
Lets assume we have the following class:
class DataBase
{
public:
DataBase();
void addEntry(const std::string& key, double value);
double getEntry(const std::string& key);
protected:
std::map<std::string, double> table;
};
There is another class which holds a pointer to an instance of DataBase
class:
class SomeClass
{
protected:
DataBase *someDataBase;
};
Here I get confused, as two options come to my mind:
- Each instance of
SomeClass
will have a database of its own. In the sense that only the data added by this instance will be present in this database (dedicated databases). - Each instance of
SomeClass
will be referring to a central database. Data added by any of the instances ofSomeClass
will be in one single database (a global database).
Question:
- What is the name of the aforementioned concepts in OOP?
- How each of the aforementioned approaches can be achieved in C++
1 is object composition.
2 needs another Database* declaration in SomeClass declaration, and both pointers must be initialized.
I don't know whether the concept itself has a name, but the members are referred to as static or non-static.
Your 1. would be non-static and your 2. would be static.
As for how to implement this, you seem to know how to go about the non-static variant, and for the static one, just use the
static
keyword in the member declaration:Static members can be accessed with
::
, likeSomeClass::someDataBase
.Initializing static members in C++ is not that straightforward though, see this question.
What you are looking for is the topic of ownership in C++. When I say ownership, I mean who is responsible for managing the memory that holds the object.
In your first example each
SomeClass
could own its ownDataBase
.This
SomeClass
either takes ownership of the DataBase given to it or creates its own (practically you usually do one or the other). This means you can pass in aDataBase
object (using a concept known as dependency injection):or just let the class create the
DataBase
object:In the above example you don't have to worry about disposal of the
DataBase
objects, knowing thatSomeClass
should take care of disposal in its destructor.In the other scenario you could share a
DataBase
without having it be disposed of by yourSomeClass
(whether it's global or not is irrelevant).Here we could pass multiple
SomeClass
objects the sameDataBase
and not have to worry about them being disposed of by any of the objects.In this scenario we were able to reuse the
DataBase
object before disposing of it external to ourSomeClass
objects. Practically speaking, this disposal could be managed by another class likeDataBaseStore
, allowing you to have a reliable way to handle and reuseDataBase
objects.With Composition you can just have the
DataBase
as a member:With Dependency injection you basically give
SomeClass
a pointer to your sharedDataBase
andSomeClass
saves a pointer to it. Be careful if you have a multithreaded application, you need to protect writing to the database and maybe reading as well.How you crate and where you store the shared
DataBase
is up to you.I will address both of your options:
You have that with your current setup. Each instance of
SomeClass
will have a pointer to aDataBase
class.In order to achieve this, you have to take
DataBase
out of yourSomeClass
, sinceSomeClass
no longer owns the database. You will utilize the singleton design pattern for yourDataBase
class to say "there is only one instance of this class at any one time".To do that, you will write your database class like so:
To implement the
instance()
method:If you would like more information on singletons, read to your heart's content here.
Concept n°1 is composition. The
Database
is part of theSomeClass
.Concept n°2 doesn't have a name as far as I know.
Implementing concept n°1 :
This is actually pretty straightworward : give
SomeClass
a member of typeDatabase
.If you need pointers (e.g for polymorphism), use a
std::unique_ptr
:Implementing concept n°2 :
This depends on the rest of the program. If you can, the simplest way is to have a static
Database
member insideSomeClass
:If
Database
can't be statically initialized, or if you don't want all of theSomeClass
es to share the sameDatabase
, you can make use of the object factory pattern :Then all
SomeClass
es created by the same factory will share the sameDatabase
.