The following is directly related to this. What I would like is to be able to call and have active only one class at a time, to save memory, but also because I plan to add, later on, a GUI, so I'd be able to call the classes through a drop-down menu (for example).
I tried making composition, and this is what came out:
#include <iostream>
class Power
{
private:
double m_x;
public:
Power() {std::cout<<"Power\n";}
Power(double x): m_x {x} {std::cout<<"Power("<<x<<")\n";}
~Power() {std::cout<<"~Power\n";}
const double getX() const { return m_x; }
};
class Scanner
{
private:
Power m_power;
public:
Scanner() {std::cout<<"Scanner\n";}
Scanner(const Power &p): m_power {p} {std::cout<<"Scanner("<<&p<<")\n";}
void print() {std::cout<<"x="<<m_power.getX()<<'\n';}
};
class Printer
{
private:
Power m_power;
public:
Printer() {std::cout<<"Printer\n";}
Printer(const Power &p): m_power {p} {std::cout<<"Printer("<<&p<<")\n";}
void print() {std::cout<<"x="<<m_power.getX()<<'\n';}
};
class Copier // if Copier is to be used for "unification", will "public" be needed?
{
private:
Scanner *m_s;
Printer *m_p;
int m_i;
public:
Copier() {std::cout<<"Copier\n";}
Copier(const Power &p, int i): m_i {i}
{
if (i)
m_s = new Scanner(p);
else
m_p = new Printer(p);
std::cout<<"Copier("<<&p<<","<<i<<")\n";
}
void print() { std::cout << (m_i ? m_s->getX() : m_p->getX()) << '\n'; }
};
int main(int argc, char *argv[])
{
Scanner *s {new Scanner(Power(2.3))};
s->print();
Printer *p {new Printer(Power(3.14))};
p->print();
s->print(); // here, both *s and *p exist, both use memory
// this comes after considering adding class Copier
Copier *c {new Copier(Power(1.618), 0)};
c->print();
c = new Copier(Power(2.718), 1);
c->print();
return 0;
}
Ignore Copier
for a bit. As it is, I can use it, and this is what comes out:
Power(2.3)
Scanner(0x7ffc80d98c10)
~Power
x=2.3
Power(3.14)
Printer(0x7ffc80d98c20)
~Power
x=3.14
x=2.3
The (major) problem now is that there are multiple objects in memory, there's *s
and there's *p
, as you can see x
can pe printed out with both 3.14
and 2.3
. If I have more than 2 classes (which I do), I could call each class and each will take up memory. That's not something I want.
How can I call only one class at a time and not have to call extra resets or deletes? I thought of adding another class for it, see Copier
. But I can't use std::unique_ptr
and the solution in the code is, not only extremely ugly, but doesn't even work. Plus it calls constructors like crazy.
I tried using std::unique_ptr
in a simple function, with std::make_unique
(that needs c++14
, and I'd rather keep some larger safety margin, but I could also live with it, too). It also doesn't work because it points to Power
(if I call z->print()
it says 'class Power' has no member 'print'
):
std::unique_ptr<Power> call(const Power &p, const int &i)
{
if (i)
return std::make_unique<Printer>(p);
else
return std::make_unique<Scanner>(p);
}
I don't know how to make this. In short, classes Scanner
, Printer
, and any other that exist, are dedicated classes that perfom one task, only, unique in their way of computing, and all of them make use of some common variables in Power
(besides their own). I don't think it would be very effective to move the common variables to each class because they would only bloat the code, and, as I understand it, "if you can use a storage class instead of repeating the same variable over and over, use it" (not my words, is this true?). Then, I'd like to be able to instantiate those classes, but only have one active at a time, to spare memory.
As an example, suppose one class makes an array of 1mil values, then another makes 1mil different values, and so on. Imagine having that array in memory as many times as there are instantiated classes. I don't want that. The purpose of Copier
would have been to call (based on the conditional) only one class at a time. Job done? Call another, but forget anything else that was done before, start anew. And all this to be able to call through only one widget, such as select from list, click&go, that will be added later.
That was a stupid mistake, I forgot to delete public ...
after copy-pasting. I also tried the code now (with Copier
), it compiles, but still doesn't work, m_x
stays empty, even with the very ugly solution of having two Scanner
and Printer
pointers as member variables inside Copier
.
Well, after some tries, I couldn't make what I wanted so I thought to go back to my original idea, even if it meant inheritance. So I came up with this piece of code, where I changed the names to make a bit more sense(?):
#include <iostream>
class Garage
{
protected:
double m_x; // gas, tires, etc, that all cars use, reside in the Garage
public:
Garage() {std::cout<<"Garage\n";}
virtual ~Garage() {std::cout<<"~Garage\n";}
};
class Audi: virtual public Garage
{
public:
Audi() {std::cout<<"Audi\n";}
void f(const double &x) { m_x=x; std::cout<<"Audi::f("<<x<<")\n";}
};
class Bmw: virtual public Garage
{
public:
Bmw() {std::cout<<"Bmw\n";}
void f(const double &x) { m_x=x; std::cout<<"Bmw::f("<<x<<")\n";}
};
class Driver: public Audi, public Bmw
{
private:
double m_y; // report of driving, based on m_x
public:
Driver() {std::cout<<"Driver\n";}
Driver(const double &x, int i)
{
if (i)
Bmw::f(x);
else
Audi::f(x);
m_y = -m_x;
std::cout<<"Driver("<<x<<","<<i<<")\n";
}
void print() { std::cout << "x=" << m_x << ", y=" << m_y << '\n'; }
};
int main(int argc, char *argv[])
{
Driver *d {new Driver(1.618, 0)};
d->print();
d = new Driver(0.618, 1);
d->print();
// even iteration works now
delete d;
d = nullptr; // to be sure it's dead(?)
for (int i=0; i<2; ++i)
{
d = new Driver(3.14, i);
d->print();
}
return 0;
}
Now, this works, but I have a feeling I set a new record on bad code example. Please don't bash me for this, rather point out all the mistakes, or how you would do it to achieve the same result. Still, even if it seems to work as I want, it still calls all the constructors, on all branches, instead of only on the needed ones. I realize (my apologies) I forgot to say that Driver
, here, is also responsible for using m_x
further, for its m_y
(that's why the code is a bit different).
I'd like to point out that I am not fixed in keeping this code, or any other, I am willing to change and adapt, as long as I reach my purpose. But since I am a beginner, I can't make too many combinations, so I am left with presenting whichever result it is that I reached to try and make myself understood. The program above, as it is, when run, gives what I want, even has the possibility of making a loop, which will let me use it much easier in a GUI, later on. The names, as they are, make the most sense in composition, Garage
has-a Bmw
, and that was what I tried, but I couldn't obtain what I wanted. So, even if this uses inheritance and does not make sense that an Audi
is-a Garage
, I kept the names to suggest my initial tryout with composition. My main reason for posting this is to show what I would like the program to do. What happens in main()
will be used in a GUI, I am thinking of Qt, because I'd like this to run on all 3 major OSes. So having the possibility of calling one car at a time, using it, and also being able to store previous information without having stale objects in memory, only m_x
*nr_of_cars, will make it much easier to work with.