diff options
feat(Week10): Add solutions
7 files changed, 403 insertions, 0 deletions
| -rw-r--r-- | Week10/Exercise02/CombustionVehicle.cpp | 69 | ||||
| -rw-r--r-- | Week10/Exercise02/CombustionVehicle.h | 27 | ||||
| -rw-r--r-- | Week10/Exercise02/ElectricVehicle.cpp | 79 | ||||
| -rw-r--r-- | Week10/Exercise02/ElectricVehicle.h | 31 | ||||
| -rw-r--r-- | Week10/Exercise02/Vehicle.cpp | 74 | ||||
| -rw-r--r-- | Week10/Exercise02/Vehicle.h | 66 | ||||
| -rw-r--r-- | Week10/Exercise02/main.cpp | 57 |
diff --git a/Week10/Exercise02/CombustionVehicle.cpp b/Week10/Exercise02/CombustionVehicle.cpp new file mode 100644 index 0000000..b431161 --- /dev/null +++ b/Week10/Exercise02/CombustionVehicle.cpp @@ -0,0 +1,69 @@ +#include "CombustionVehicle.h" + +CombustionVehicle::CombustionVehicle() : Vehicle(), cyllindersCount(), engineVolume() { + type = 2; +} + +unsigned CombustionVehicle::GetCyllindersCount() const { + return cyllindersCount; +} + +void CombustionVehicle::SetCyllindersCount(unsigned cyllindersCount) { + this->cyllindersCount = cyllindersCount; +} + +double CombustionVehicle::GetEngineVolume() const { + return engineVolume; +} + +void CombustionVehicle::SetEngineVolume(double engineVolume) { + this->engineVolume = engineVolume; +} + +std::ostream& operator<<(std::ostream& ostr, const CombustionVehicle& vehicle) { + ostr << (const Vehicle&)vehicle + << "Cyllinders count: " << vehicle.cyllindersCount << std::endl + << "Engine volume: " << vehicle.engineVolume << std::endl; + return ostr; +} + +std::istream& operator>>(std::istream& istr, CombustionVehicle& vehicle) { + istr >> (Vehicle&)vehicle + >> vehicle.cyllindersCount + >> vehicle.engineVolume; + return istr; +} + +bool CombustionVehicle::IsCombustionVehicle(const Vehicle& vehicle) { + // Как работят конвертиранията: в C++ има няколко конвертирания, те са главно + // const_cast, static_cast и reinterpret_cast. + // Стандартното конвертиране със скоби "(Type)(x)", се нарича експлицитно + // конвертиране и идва от C. Под C++, то просто пробва всички възможни + // конвертирания, докато някое е валидно (дори и като резултат да е грешно). + // + // const_cast конветира между това дали тип е константен или не. + // static_cast променя как поглеждаме посочената памет. С други думи, + // "тези битове/байтове тук вече трябва да се зачитат за този тип". + // reinterpret_cast прави по-сложна промяна, която цели да върне такива + // данни, че всичко да работи коректно. На теория, може и примерно да се + // задели нова памет в която да се пренесат данните които са ни предоставени. + // + // В нашия случай, CombustionVehicle има повече член-данни от vehicle, което + // означава че ако използваме static_cast (което експлицитното конвертиране + // ще избере), ще направим грешка. + // Един Vehicle обект заема ~1042 байта, докато CombustionVehicle заема ~1054. + // Това означава, че със static_cast ще зачитаме памет от 1042 байта като + // такава от 1054 и можем да пишем/четем извън предопределените адреси памет. + // + // В нашия случай това няма да се случи, но коректното решение е да + // използваме reinterpret_cast, който ще осигури че всичко от върнатата + // стойност може да се достъпи, без проблеми. + // + // + // А защо ни трябва конвертиране, нали CombustionVehicle е наследник, + // не можем ли директно от vehicle да вземем type? + // Еми, не можем, защото член-функция може да достъпва само член-данни и член-функции + // на обекти от същия тип. Т.е. няма никакъв специален достъп към Vehicle обекти, + // само всичко публично е налично, но има пълен достъп към CombustionVehicle обекти. + return reinterpret_cast<const CombustionVehicle&>(vehicle).type == 2; +} diff --git a/Week10/Exercise02/CombustionVehicle.h b/Week10/Exercise02/CombustionVehicle.h new file mode 100644 index 0000000..7c102be --- /dev/null +++ b/Week10/Exercise02/CombustionVehicle.h @@ -0,0 +1,27 @@ +#ifndef _COMBUSTIONVEHICLE +#define _COMBUSTIONVEHICLE + +#include "Vehicle.h" +#include <istream> +#include <ostream> + +class CombustionVehicle : public Vehicle { + unsigned cyllindersCount; + double engineVolume; + +public: + CombustionVehicle(); + + unsigned GetCyllindersCount() const; + void SetCyllindersCount(unsigned cyllindersCount); + + double GetEngineVolume() const; + void SetEngineVolume(double engineVolume); + + friend std::ostream& operator<<(std::ostream& ostr, const CombustionVehicle& vehicle); + friend std::istream& operator>>(std::istream& istr, CombustionVehicle& vehicle); + + static bool IsCombustionVehicle(const Vehicle& vehicle); +}; + +#endif /* _COMBUSTIONVEHICLE */ diff --git a/Week10/Exercise02/ElectricVehicle.cpp b/Week10/Exercise02/ElectricVehicle.cpp new file mode 100644 index 0000000..deb3179 --- /dev/null +++ b/Week10/Exercise02/ElectricVehicle.cpp @@ -0,0 +1,79 @@ +#include "ElectricVehicle.h" + +ElectricVehicle::ElectricVehicle() : Vehicle(), batteryCapacity(), range(), chargingCapacity() { + type = 1; +} + +double ElectricVehicle::GetBatteryCapacity() const { + return batteryCapacity; +} + +void ElectricVehicle::SetBatteryCapacity(double batteryCapacity) { + this->batteryCapacity = batteryCapacity; +} + +double ElectricVehicle::GetRange() const { + return range; +} + +void ElectricVehicle::SetRange(double range) { + this->range = range; +} + +double ElectricVehicle::GetCharingCapacity() const { + return chargingCapacity; +} + +void ElectricVehicle::SetChargingCapacity(double chargingCapacity) { + this->chargingCapacity = chargingCapacity; +} + +std::ostream& operator<<(std::ostream& ostr, const ElectricVehicle& vehicle) { + ostr << (const Vehicle&)vehicle + << "Battery capacity: " << vehicle.batteryCapacity << std::endl + << "Range: " << vehicle.range << std::endl + << "Charging capacity: " << vehicle.chargingCapacity << std::endl; + return ostr; +} + +std::istream& operator>>(std::istream& istr, ElectricVehicle& vehicle) { + istr >> (Vehicle&)vehicle + >> vehicle.batteryCapacity + >> vehicle.range + >> vehicle.chargingCapacity; + return istr; +} + +bool ElectricVehicle::IsElectricVehicle(const Vehicle& vehicle) { + // Как работят конвертиранията: в C++ има няколко конвертирания, те са главно + // const_cast, static_cast и reinterpret_cast. + // Стандартното конвертиране със скоби "(Type)(x)", се нарича експлицитно + // конвертиране и идва от C. Под C++, то просто пробва всички възможни + // конвертирания, докато някое е валидно (дори и като резултат да е грешно). + // + // const_cast конветира между това дали тип е константен или не. + // static_cast променя как поглеждаме посочената памет. С други думи, + // "тези битове/байтове тук вече трябва да се зачитат за този тип". + // reinterpret_cast прави по-сложна промяна, която цели да върне такива + // данни, че всичко да работи коректно. На теория, може и примерно да се + // задели нова памет в която да се пренесат данните които са ни предоставени. + // + // В нашия случай, ElectricVehicle има повече член-данни от vehicle, което + // означава че ако използваме static_cast (което експлицитното конвертиране + // ще избере), ще направим грешка. + // Един Vehicle обект заема ~1042 байта, докато ElectricVehicle заема ~1054. + // Това означава, че със static_cast ще зачитаме памет от 1042 байта като + // такава от 1054 и можем да пишем/четем извън предопределените адреси памет. + // + // В нашия случай това няма да се случи, но коректното решение е да + // използваме reinterpret_cast, който ще осигури че всичко от върнатата + // стойност може да се достъпи, без проблеми. + // + // + // А защо ни трябва конвертиране, нали ElectricVehicle е наследник, + // не можем ли директно от vehicle да вземем type? + // Еми, не можем, защото член-функция може да достъпва само член-данни и член-функции + // на обекти от същия тип. Т.е. няма никакъв специален достъп към Vehicle обекти, + // само всичко публично е налично, но има пълен достъп към ElectricVehicle обекти. + return reinterpret_cast<const ElectricVehicle&>(vehicle).type == 1; +} diff --git a/Week10/Exercise02/ElectricVehicle.h b/Week10/Exercise02/ElectricVehicle.h new file mode 100644 index 0000000..5a48b27 --- /dev/null +++ b/Week10/Exercise02/ElectricVehicle.h @@ -0,0 +1,31 @@ +#ifndef _ELECTRICVEHICLE +#define _ELECTRICVEHICLE + +#include "Vehicle.h" +#include <istream> +#include <ostream> + +class ElectricVehicle : public Vehicle { + double batteryCapacity; + double range; + double chargingCapacity; + +public: + ElectricVehicle(); + + double GetBatteryCapacity() const; + void SetBatteryCapacity(double batteryCapacity); + + double GetRange() const; + void SetRange(double range); + + double GetCharingCapacity() const; + void SetChargingCapacity(double chargingCapacity); + + friend std::ostream& operator<<(std::ostream& ostr, const ElectricVehicle& vehicle); + friend std::istream& operator>>(std::istream& istr, ElectricVehicle& vehicle); + + static bool IsElectricVehicle(const Vehicle& vehicle); +}; + +#endif /* _ELECTRICVEHICLE */ diff --git a/Week10/Exercise02/Vehicle.cpp b/Week10/Exercise02/Vehicle.cpp new file mode 100644 index 0000000..bbc6bf0 --- /dev/null +++ b/Week10/Exercise02/Vehicle.cpp @@ -0,0 +1,74 @@ +#include "Vehicle.h" +#include <cstring> + +Vehicle::Vehicle() : model(), yearOfManufacture(), mileage(), ecoCategory(), weight(), horsePower() { + type = 0; +} + +const char* Vehicle::GetModel() const { + return model; +} + +void Vehicle::SetModel(char model[MODEL_LENGTH]) { + strcpy(this->model, model); +} + +unsigned Vehicle::GetYearOfManufacture() const { + return yearOfManufacture; +} + +void Vehicle::SetYearOfManufacture(unsigned yearOfManufacture) { + this->yearOfManufacture = yearOfManufacture; +} + +double Vehicle::GetMileage() const { +return mileage; +} + +void Vehicle::SetMileage(double mileage) { + this->mileage = mileage; +} + +unsigned short Vehicle::GetEcoCategory() const { + return ecoCategory; +} + +void Vehicle::SetEcoCategory(unsigned short ecoCategory) { + this->ecoCategory = ecoCategory; +} + +double Vehicle::GetWeight() const { + return weight; +} + +void Vehicle::SetWeight(double weight) { + this->weight = weight; +} + +double Vehicle::GetHorsePower() const { + return horsePower; +} + +void Vehicle::SetHorsePower(double horsePower) { + this->horsePower = horsePower; +} + +std::ostream& operator<<(std::ostream& ostr, const Vehicle& vehicle) { + ostr << vehicle.model << std::endl + << "Manufactured: " << vehicle.yearOfManufacture << std::endl + << "Mileage: " << vehicle.mileage << std::endl + << "Eco category: " << vehicle.ecoCategory << std::endl + << "Weight: " << vehicle.weight << std::endl + << "Horse power: " << vehicle.horsePower << std::endl; + return ostr; +} + +std::istream& operator>>(std::istream& istr, Vehicle& vehicle) { + istr.getline(vehicle.model, MODEL_LENGTH); + istr >> vehicle.yearOfManufacture + >> vehicle.mileage + >> vehicle.ecoCategory + >> vehicle.weight + >> vehicle.horsePower; + return istr; +} diff --git a/Week10/Exercise02/Vehicle.h b/Week10/Exercise02/Vehicle.h new file mode 100644 index 0000000..206e1b5 --- /dev/null +++ b/Week10/Exercise02/Vehicle.h @@ -0,0 +1,66 @@ +#ifndef _VEHICLE +#define _VEHICLE + +#include <istream> +#include <ostream> + +const unsigned MODEL_LENGTH = 1024; + +class Vehicle { + char model[MODEL_LENGTH]; + unsigned yearOfManufacture; + double mileage; + unsigned short ecoCategory; + double weight; + double horsePower; + + +public: + Vehicle(); + + const char* GetModel() const; + void SetModel(char model[MODEL_LENGTH]); + + unsigned GetYearOfManufacture() const; + void SetYearOfManufacture(unsigned yearOfManufacture); + + double GetMileage() const; + void SetMileage(double mileage); + + unsigned short GetEcoCategory() const; + void SetEcoCategory(unsigned short ecoCategory); + + double GetWeight() const; + void SetWeight(double weight); + + double GetHorsePower() const; + void SetHorsePower(double horsePower); + + // Имаме всички нужни селектори и мутатори, за да не се нуждаем + // от това операторите да са friend. Но въпреки това ще го + // имплементираме така. + + friend std::ostream& operator<<(std::ostream& ostr, const Vehicle& vehicle); + friend std::istream& operator>>(std::istream& istr, Vehicle& vehicle); + + // След като създадем динамично-заделен обект от + // клас наследник, можем да конвертираме указателя към + // базовия клас (т.е. CombustionVehicle* да стане Vehicle*). + // В този случай, ще имаме налични само нещата, които са + // достъпни във Vehicle, включително деструктора. + // + // Но CombustionVehicle има още член-данни, как ще разберем, + // че Vehicle* е всъщност CombustionVehicle*? + // Коректното решение, като стигнем до там, е да използваме + // виртуални деструктури. + // + // Текущото решение, което можем да направим, е да запазваме + // някаква допълнителна стойност, която е различна спрямо + // конкретния клас (наследник). След това ще правим проверки по + // нея, дали съответства на тази на даден клас, и ако да, конвертираме. +protected: + unsigned type; +}; + + +#endif /* _VEHICLE */ diff --git a/Week10/Exercise02/main.cpp b/Week10/Exercise02/main.cpp new file mode 100644 index 0000000..980b9b2 --- /dev/null +++ b/Week10/Exercise02/main.cpp @@ -0,0 +1,57 @@ +#include "Vehicle.h" +#include "CombustionVehicle.h" +#include "ElectricVehicle.h" +#include <iostream> + +int main() { + unsigned N; + std::cin >> N; + + Vehicle** vehicles = new Vehicle*[N]; + for (unsigned i = 0; i < N; ++i) { + char type; + std::cin >> type; + std::cin.ignore(); + + if (type == 'c') { + CombustionVehicle* vehicle = new CombustionVehicle; + std::cin >> *vehicle; + vehicles[i] = vehicle; + } + else if (type == 'e') { + ElectricVehicle* vehicle = new ElectricVehicle; + std::cin >> *vehicle; + vehicles[i] = vehicle; + } + else { + vehicles[i] = nullptr; + } + } + + for (unsigned i = 0; i < N; ++i) { + if (vehicles[i] != nullptr) + std::cout << *vehicles[i]; + } + + for (unsigned i = 0; i < N; ++i) { + if (vehicles[i] == nullptr) { + continue; + } + // Това го правим, защото delete само вижда че обекта е "Vehicle", + // не вижда допълнителната памет, която се заделя за допълнителните + // член-данни, които запазваме при Combustion и Electric. + + else if (CombustionVehicle::IsCombustionVehicle(*vehicles[i])) { + delete (CombustionVehicle*)vehicles[i]; + } + else if (ElectricVehicle::IsElectricVehicle(*vehicles[i])) { + delete (ElectricVehicle*)vehicles[i]; + } + else { + delete vehicles[i]; + } + } + delete[] vehicles; + + return 0; +} |
