-1

Basically my issue is with compositions. I understand the principle, but I'm struggling with the execution in one of the tests.

From the code of Computer and Monitor below, I have to create a final class Complect which will have its own name , the name of the computer, the name of the monitor, and a price which will be made up from the price() functions.

Computer.h

#ifndef COMPUTER_H
#define COMPUTER_H
#include <string>

class Computer{

public:
    Computer(std::string name, int ram, double price); 

    std::string name() const; 
    int ram() const;
    double price() const;


    void printComputer() const;

    void setComputer(std::string name, int ram, double price);

private:
    std::string its_name;
    int ram_gb;

    double cost_price;
};
#endif // COMPUTER_H

Computer.cpp

#include "Computer.h"
#include <iostream>

Computer::Computer(std::string name, int ram, double price)
: its_name(name), ram_gb(ram), cost_price(price){
}

std::string Computer::name() const {
    return its_name;
}

int Computer::ram() const {
    return ram_gb;
}

double Computer::price() const {
    return cost_price;
}

void Computer::printComputer() const{ 
    std::cout << "Computer name = " <<name() <<"\n"
    << "Computer RAM = " <<ram() <<" GB\n"
    << "Computer Price = " << price() <<" EUR \n";
}

Monitor.h

#ifndef MONITOR_H
#define MONITOR_H
#include <string>

class Monitor{

public:
    Monitor(std::string name, std::string type, double price);

    std::string name() const;
    std::string type() const;
    double price() const;

    //print computer
    void printMonitor() const;

    //set computer
    void setMonitor(std::string name, std::string type, double price);

private:
    std::string its_name;
    std::string type_set;

    double cost_price;
};

#endif // MONITOR_H

Monitor.cpp

#include "Monitor.h"
#include <iostream>

Monitor::Monitor(std::string name, std::string type, double price) : its_name(name), type_set(type), cost_price(price){
}

std::string Monitor::name() const {
    return its_name;
}

std::string Monitor::type() const{
    return type_set;
}

double Monitor::price() const {
    return cost_price;
}

void Monitor::printMonitor() const{
    std::cout << "Monitor name = " <<name() <<"\n"
    << "Monitor type = " <<type() <<"\n"
    << "Monitor price = " << price() <<" EUR \n";
}

Here is the class that I have made:

Complect.h

#ifndef COMPLECT_H
#define COMPLECT_H
#include <string>

class Complect{

public:
    Complect(std::string name, std::string computername, std::string monitorname,  double price);
    std::string name() const;
    std::string computername() const;
    std::string monitorname() const;
    double price() const;

    void printComplect();

    void setComplect(std::string name, std::string computername, std::string monitorname, double price);

private:
    std::string complect_name;
    std::string computername_final;
    std::string monitorname_final;
    double cost_price;

};

#endif // COMPLECT_H

Complect.cpp

#include "Complect.h"
#include "Monitor.h"
#include "Computer.h"
#include <iostream>

Complect::Complect(std::string name, std::string computername, std::string monitorname, double price) :
complect_name(name), computername_final(computername), monitorname_final(monitorname), cost_price(price){
}

std::string Complect::name() const{
    return complect_name;
}

std::string Complect::computername() const{
    return computername_final;
}

std::string Complect::monitorname() const{
    return monitorname_final;
}

double Complect::price() const{
    return cost_price;
}

void Complect::printComplect(){
    std::cout << "Complect name = " << name() <<"\n"
    << "Computer name = " <<computername() <<"\n"
    <<"Monitor name = " <<monitorname() <<"\n"
    <<"Complect price = " <<price() <<" EUR \n";
}

Here is how I use the classes in Main.cpp

#include <iostream>
#include "Computer.h"
#include "Monitor.h"
#include "Complect.h"

int main(){

    Computer asus("Asus One", 8, 545.95) ;
    asus.printComputer() ; 
    std::cout << "\n";

    Monitor iiyama("Iiyama Blackhawk 27inch", "LED", 299.99);
    iiyama.printMonitor();
    std::cout <<"\n";

    Complect numberOne ("Number one complect", asus.name(), iiyama.name(), iiyama.price() + asus.price());
    numberOne.printComplect();
    std::cout <<"\n";

system ("pause");
return 0;
}

The end result is what it should be, so this code works. But the issue with this is that it's incorrectly structured.

In the main.cpp file you will see that the Complect object is being created. But I currently provide all of the informations of that object at construction in main.cpp file.

Sorry the codes a bit messy, but im trying to wrap my head around this and struggling at the moment... How to make the class in complect.cpp file provide itself all its information ?

Christophe
  • 68,716
  • 7
  • 72
  • 138
B. Baxter
  • 133
  • 1
  • 10
  • 1
    _the codes a bit messy_ not at all, it is clean, compile without warning and using const method, so rare, so I upvote it .. before to answer – bruno Apr 06 '19 at 13:48
  • 1
    Guys I really do not understand why you want to close that question, it is a serious question and it absolutely not out of the scope of S.O. questions :-) – bruno Apr 06 '19 at 14:08
  • I have slightly edited the question so to better highlight your issue and remove a couple of ambiguous formulations. Please check if it's still ok for you. – Christophe Apr 06 '19 at 17:33

1 Answers1

1

Currently you do not use composition but copy the attributes from the two other classes and you do a lot of work in the call of the constructor from main

A first little change from your code is to get instances of Computer and Monitor in parameter in the constructor:

Complect(std::string name, const Computer &, const Monitor &);

of course the final price is also computed inside that constructor, in main you just create a Complect with its name and its parts :

Complect numberOne ("Number one complect", asus, iiyama);

Now main fortunately does not have to know how the price is computed, else imagine if the formula change and you have to update all the calls of the constructor :-(. The way the price is computed is only the responsibility of Complect.

Complect numberOne ("Number one complect", asus, iiyama);

More than the constructor setComplect must be updated to receive the price of the monitor and computer separated for the same reason.

void setComplect(std::string name, std::string computername, std::string monitorname, double computerprice, double monitorprice);

or probably better to replace it by the methods

void setname(std::string name);
void setcomputer(std::string computername, double computerprice);
void setmonitor(std::string monitorname, double monitorprice);

But to duplicate all the attributes of Computer and Monitor in Complect is not practical, and you do not have composition to the instances. A first possibility is to save a copy of them :

class Complect{
  ...
  private:
     Computer computer;
     Monitor monitor;
     // does not need attribute "double cost_price;"
  ...
};

Complect::Complect(std::string name, const Computer & c, const Monitor & m)
   : complect_name(name), computer(c), monitor(m) {
}

std::string Complect::computername() const{
    return computer.name();
}

std::string Complect::monitorname() const{
    return monitor.name();
}

double Complect::price() const{
    return computer.price() + monitor.price();
}

void Complect::printComplect(){
    std::cout << "Complect name = " << name() <<"\n"
    << "Computer name = " << computer.name() <<"\n"
    <<"Monitor name = " << monitor.name() <<"\n"
    <<"Complect price = " << price() <<" EUR \n";
}

The advantage of that solution is you are not impacted if the initial instances of Monitor and Computer disappear. The disadvantage is for instance the price is not updated if the price of one of the cloned part changes except by calling setXXX


An other way is to not clone the Monitor and Conputer, but you cannot have just that :

class Complect{
  ...
  private:
     Computer & computer;
     Monitor & monitor;
     // does not need attribute "double cost_price;"
  ...
};

Complect::Complect(std::string name, const Computer & c, const Monitor & m)
   : complect_name(name), computer(c), monitor(m) {
}

because that supposes the instances of Monitor and Computer still exist while the corresponding instance of Complect exists

Fortunately C++ offers interesting features to manage that

bruno
  • 32,421
  • 7
  • 25
  • 37
  • This makes so much more sense now.... Thanks Bruno. With this, its working now in this way. – B. Baxter Apr 06 '19 at 14:44
  • @B.Baxter ok, I edited again my answer after your accept and I let you continue :-) – bruno Apr 06 '19 at 14:56
  • A nice, didactic and helpful answer for people less familiar with C++/oop, and who are also welcome on SO. Well done ! – Christophe Apr 06 '19 at 17:09
  • @Christophe thank you, I was about to continue speaking about `shared_ptr` etc but the OP stopped me accepting my answer :-) – bruno Apr 06 '19 at 17:11