Programming Language & Its Applications β Features of Object-Oriented Programming, NEC licence examination syllabus (Nepal Engineering Council).
A derived class reuses and extends a base class β the "is-a" relationship, with three access modes and one famous trap.
QPushButton inherits QAbstractButton inherits QWidget inherits QObject β four levels, and that is why every widget can be positioned, painted and given a parent without each class reimplementing it. The C++ standard library uses it too: std::ifstream inherits std::istream, which is why getline(file, line) and getline(cin, line) are the same function. But inheritance is also the most overused feature in OOP β search "composition over inheritance" after this page. It is the single most valuable design lesson in the whole subject, and it will make your project work better.#include <iostream>
class Base {
private:
int priv = 1;
protected:
int prot = 2;
public:
int publ = 3;
void show() const {
std::cout << " Base: " << priv << " " << prot
<< " " << publ << "\n";
}
};
class PubDerived : public Base {
public:
void test() {
/* std::cout << priv; β private in Base */
std::cout << " PubDerived sees prot=" << prot
<< " publ=" << publ << "\n";
}
};
class PrivDerived : private Base {
public:
void test() {
/* accessible INSIDE, but publ is now private,
so outsiders cannot reach it through PrivDerived */
std::cout << " PrivDerived sees prot=" << prot
<< " publ=" << publ << "\n";
}
};
class GrandChild : public PubDerived {
public:
void test() {
/* protected survives one more level */
std::cout << " GrandChild sees prot=" << prot << "\n";
}
};
int main() {
PubDerived a; a.test();
PrivDerived b; b.test();
GrandChild c; c.test();
std::cout << "outside: a.publ = " << a.publ << "\n";
/* std::cout << b.publ; β publ became private
in PrivDerived */
a.show(); /* public method inherited */
/* b.show(); β also private now */
return 0;
}
Output:
PubDerived sees prot=2 publ=3
PrivDerived sees prot=2 publ=3
GrandChild sees prot=2
outside: a.publ = 3
Base: 1 2 3
#include <iostream>
#include <string>
#include <cmath>
/* BASE: what every shape has in common */
class Shape {
protected:
std::string name;
public:
Shape(std::string n) : name(std::move(n)) {}
/* virtual so derived versions are called through a
Shape* β covered fully in the next section */
virtual double area() const { return 0.0; }
virtual double perimeter() const { return 0.0; }
void describe() const {
std::cout << " " << name
<< ": area=" << area()
<< " perim=" << perimeter() << "\n";
}
virtual ~Shape() = default;
};
class Rectangle : public Shape {
protected:
double w, h;
public:
Rectangle(double a, double b)
: Shape("Rectangle"), w(a), h(b) {}
double area() const override { return w * h; }
double perimeter() const override { return 2*(w+h); }
};
/* MULTILEVEL: Square from Rectangle from Shape */
class Square : public Rectangle {
public:
explicit Square(double s) : Rectangle(s, s) {
name = "Square"; /* protected: reachable */
}
};
/* HIERARCHICAL: Circle also derives from Shape */
class Circle : public Shape {
double r;
public:
explicit Circle(double rad) : Shape("Circle"), r(rad) {}
double area() const override { return M_PI * r * r; }
double perimeter() const override { return 2 * M_PI * r; }
};
int main() {
Rectangle a(4, 6);
Square b(5);
Circle c(3);
a.describe(); b.describe(); c.describe();
/* a Square IS-A Rectangle IS-A Shape */
Shape *shapes[] = { &a, &b, &c };
double total = 0;
for (Shape *s : shapes) total += s->area();
std::cout << " total area = " << total << "\n";
return 0;
}
Output:
Rectangle: area=24 perim=20
Square: area=25 perim=20
Circle: area=28.2743 perim=18.8496
total area = 77.2743
#include <iostream>
class Person {
protected:
std::string name;
public:
Person(std::string n) : name(std::move(n)) {
std::cout << " Person(" << name << ")\n";
}
void greet() const {
std::cout << " I am " << name << "\n";
}
};
/* NON-virtual inheritance -> TWO Person copies in Assistant */
class Student : public Person {
public:
Student(std::string n) : Person(n + "/student") {}
};
class Teacher : public Person {
public:
Teacher(std::string n) : Person(n + "/teacher") {}
};
class Assistant : public Student, public Teacher {
public:
Assistant(std::string n) : Student(n), Teacher(n) {}
};
/* VIRTUAL inheritance -> ONE shared Person */
class VPerson {
protected:
std::string name;
public:
VPerson(std::string n = "?") : name(std::move(n)) {
std::cout << " VPerson(" << name << ")\n";
}
void greet() const {
std::cout << " I am " << name << "\n";
}
};
class VStudent : virtual public VPerson {
public:
VStudent(std::string n) : VPerson(std::move(n)) {}
};
class VTeacher : virtual public VPerson {
public:
VTeacher(std::string n) : VPerson(std::move(n)) {}
};
class VAssistant : public VStudent, public VTeacher {
public:
/* the MOST DERIVED class initialises the virtual base */
VAssistant(std::string n)
: VPerson(n), VStudent(n), VTeacher(n) {}
};
int main() {
std::cout << " non-virtual Assistant:\n";
Assistant a("Ram");
/* a.greet(); β error: request for member 'greet'
is ambiguous β two Person copies */
a.Student::greet();
a.Teacher::greet();
std::cout << " sizeof(Assistant) = " << sizeof(Assistant)
<< "\n\n";
std::cout << " virtual VAssistant:\n";
VAssistant v("Sita");
v.greet(); /* β unambiguous: ONE VPerson */
std::cout << " sizeof(VAssistant) = " << sizeof(VAssistant)
<< "\n";
return 0;
}
Output:
non-virtual Assistant:
Person(Ram/student)
Person(Ram/teacher)
I am Ram/student
I am Ram/teacher
sizeof(Assistant) = 64
virtual VAssistant:
VPerson(Sita)
sizeof(VAssistant) = 48
using#include <iostream>
class Base {
public:
void f() { std::cout << " Base::f()\n"; }
void f(int x) { std::cout << " Base::f(" << x << ")\n"; }
void g() { std::cout << " Base::g()\n"; }
};
class Bad : public Base {
public:
/* declaring ANY f() HIDES every Base::f overload */
void f(double d) { std::cout << " Bad::f(" << d << ")\n"; }
};
class Good : public Base {
public:
using Base::f; /* bring the base overloads back */
void f(double d) { std::cout << " Good::f(" << d << ")\n"; }
};
int main() {
Bad b;
b.f(2.5);
b.f(7); /* int -> double: Bad::f(7), NOT
Base::f(int)! */
/* b.f(); β error: no matching function β Base::f()
is HIDDEN */
b.Base::f(); /* explicit qualification works */
std::cout << " --- with using Base::f ---\n";
Good g;
g.f(2.5); /* Good::f(double) */
g.f(7); /* Base::f(int) β exact match wins */
g.f(); /* Base::f() */
return 0;
}
Output:
Bad::f(2.5)
Bad::f(7)
Base::f()
--- with using Base::f ---
Good::f(2.5)
Base::f(7)
Base::f()
virtual inheritance as its solution is a standard long answer: explain the duplicate sub-object, the ambiguity, and that the most-derived class initialises a virtual base. Also distinguish overloading, hiding and overriding.Create a free account to tick topics off, take notes as you read, watch the video lessons and get a day-by-day study plan built around your exam date.
Loadingβ¦