1. Multiple inheritance
1.1. CarJet (The Diamond Problem)
Compose a class for car with jet engine that derives from two classes, car and jet.
oop_av91_en.cpp
#include <iostream>
using namespace std;
class Vehicle {
public:
Vehicle() {
cout << "Vehicle Constructor" << endl;
}
virtual ~Vehicle() {
cout << "Vehicle Destructor" << endl;
}
virtual void accelerate() const {
cout << "Vehicle Accelerating" << endl;
}
void setAcceleration(double a) {
acceleration = a;
}
double getAcceleration() const {
return acceleration;
}
protected:
double acceleration;
};
class Car : public Vehicle {
public:
Car() {
cout << "Car Constructor" << endl;
}
virtual void accelerate() const {
cout << "Car Accelerating" << endl;
}
virtual void drive() const {
cout << "Car Driving" << endl;
}
virtual ~Car() {
cout << "Car Destructor" << endl;
}
};
class Jet : public Vehicle {
public:
Jet() {
cout << "Jet Constructor" << endl;
}
virtual ~Jet() {
cout << "Jet Destructor" << endl;
}
virtual void fly() const {
cout << "Jet flying" << endl;
}
};
class JetCar : public Car, public Jet {
public:
JetCar() {
cout << "JetCar Constructor" << endl;
}
virtual ~JetCar() {
cout << "JetCar Destructor" << endl;
}
virtual void drive() const {
cout << "JetCar driving" << endl;
}
virtual void fly() const {
cout << "JetCar flying" << endl;
}
};
void analyzeCarPerformance(Car *testVehicle) {
testVehicle->drive();
//функцијата drive() може да се повика и со покажувач кон основната и
//кон изведената класа. Oваа функција е дефинирана и во двете класи
}
void analyzeJetPerformance(Jet *testVehicle) {
testVehicle->fly();
//fly() е дефинирана и во основната и во изведената класа (Јет и JetCar)
}
int main() {
Car myCar;
Jet myJet;
JetCar myJetCar;
cout << endl << endl;
cout << "Car testing in progress" << endl;
analyzeCarPerformance(&myCar);
analyzeCarPerformance(&myJetCar);
cout << "Jet testing in progress" << endl;
analyzeJetPerformance(&myJet);
analyzeJetPerformance(&myJetCar);
cout << endl << endl;
return 0;
}
Vehicle Constructor Car Constructor Vehicle Constructor Jet Constructor Vehicle Constructor Car Constructor Vehicle Constructor Jet Constructor JetCar Constructor Car testing in progress Car Driving JetCar driving Jet testing in progress Jet flying JetCar flying JetCar Destructor Jet Destructor Vehicle Destructor Car Destructor Vehicle Destructor Jet Destructor Vehicle Destructor Car Destructor Vehicle Destructor
As we can notice when an object of class JetCar
is created, the constructor of the class Vehicle
is called twice.
Vehicle Constructor Car Constructor Vehicle Constructor Jet Constructor JetCar Constructor
Also the destructor of the class Vehicle
is called twice when a JetCar
object is destructing.
JetCar Destructor Jet Destructor Vehicle Destructor Car Destructor Vehicle Destructor
To avoid this problem with multiple inheritance a new type of virtual
inheritance is introduced when classes Car
and Jet
derive from Vehicle
.
class Car: virtual public Vehicle
...
class Jet: virtual publuc Vehicle
...
oop_av911_en.cpp
#include <iostream>
using namespace std;
class Vehicle {
public:
Vehicle() {
cout << "Vehicle Constructor" << endl;
}
virtual ~Vehicle() {
cout << "Vehicle Destructor" << endl;
}
virtual void accelerate() const {
cout << "Vehicle Accelerating" << endl;
}
void setAcceleration(double a) {
acceleration = a;
}
double getAcceleration() const {
return acceleration;
}
protected:
double acceleration;
};
class Car : virtual public Vehicle {
public:
Car(){
cout << "Car Constructor" << endl;
}
virtual void accelerate() const {
cout << "Car Accelerating" << endl;
}
virtual void drive() const {
cout << "Car Driving" << endl;
}
virtual ~Car() {
cout << "Car Destructor" << endl;
}
};
class Jet : virtual public Vehicle {
public:
Jet() {
cout << "Jet Constructor" << endl;
}
virtual ~Jet() {
cout << "Jet Destructor" << endl;
}
virtual void fly() const {
cout << "Jet flying" << endl;
}
};
class JetCar : public Car, public Jet {
public:
JetCar(){
cout << "JetCar Constructor" << endl;
}
virtual ~JetCar() {
cout << "JetCar Destructor" << endl;
}
virtual void drive() const {
cout << "JetCar driving" << endl;
}
virtual void fly() const {
cout << "JetCar flying" << endl;
}
};
void analyzeCarPerformance(Car *testVehicle) {
testVehicle->drive();
//функцијата drive() може да се повика и со покажувач кон основната и
//кон изведената класа. Oваа функција е дефинирана и во двете класи
}
void analyzeJetPerformance(Jet *testVehicle) {
testVehicle->fly();
//fly() е дефинирана и во основната и во изведената класа (Јет и JetCar)
}
int main() {
Car myCar;
Jet myJet;
JetCar myJetCar;
cout << endl << endl;
cout << "Car testing in progress" << endl;
analyzeCarPerformance(&myCar);
analyzeCarPerformance(&myJetCar);
cout << "Jet testing in progress" << endl;
analyzeJetPerformance(&myJet);
analyzeJetPerformance(&myJetCar);
cout << endl << endl;
return 0;
}
1.2. Product
Implement class Product
that has a name and price.
Implement abstract class Discount
that has two pure virtual methods for price and discounted price.
From these classes derive the following classes:
-
FoodProduct
that has additional info for the number of calories; -
DigitalProduct
that has additional info for size (in MB)
Implement external function total_discount
that will compute the total discount of few products that are on discount.
oop_av92_en.cpp
#include <iostream>
#include <cstring>
using namespace std;
class Discount {
public:
virtual float getDiscount_price() = 0;
virtual float getPrice() = 0;
};
class Product {
protected:
char name[100];
float price;
public:
Product(const char *name = "", const float price = 0) {
strcpy(this->name, name);
this->price = price;
}
float getPrice() {
return price;
}
};
class DigitalProduct : public Product, public Discount {
private:
float size;
public:
DigitalProduct(const char *name = "", const float price = 0, const float size = 0) {
strcpy(this->name, name);
this->price = price;
this->size = size;
}
// overriding functions from the base class
float getDiscount_price() {
// the discount is 10%
return 0.9 * getPrice();
}
float getPrice() {
return Product::getPrice();
}
};
class FoodProduct : public Product, public Discount {
private:
float calories;
public:
FoodProduct(const char *name = "", const float price = 0, const float calories = 0) : Product(name, price) {
this->calories = calories;
}
float getDiscount_price() {
// discount is 20%
return .8 * getPrice();
}
float getPrice() {
return Product::getPrice();
}
};
float total_discount(Discount **d, int n) {
float price = 0;
for (int i = 0; i < n; ++i) {
price += d[i]->getPrice();
}
float discount = 0;
for (int i = 0; i < n; ++i) {
discount += d[i]->getDiscount_price();
}
return price - discount;
}
int main() {
Discount **d = new Discount*[3];
d[0] = new FoodProduct("Cheese", 450, 1200);
d[1] = new FoodProduct("Wine", 780, 250);
d[2] = new DigitalProduct("WOW", 380, 400);
cout << "Difference: " << total_discount(d, 3) << endl;
for (int i = 0; i < 3; ++i) {
delete d[i];
}
delete[] d;
return 0;
}