Consider this C++ class that uses encapsulation to protect its data.
class Box {
private:
int length;
public:
void setLength(int len) { length = len; }
int getLength() { return length; }
};
int main() {
Box box;
box.setLength(10);
std::cout << box.getLength() << std::endl;
return 0;
}What will this program print?
#include <iostream> class Box { private: int length; public: void setLength(int len) { length = len; } int getLength() { return length; } }; int main() { Box box; box.setLength(10); std::cout << box.getLength() << std::endl; return 0; }
Think about how the setter and getter methods control access to the private variable.
The private variable length is set using the public method setLength. Then getLength returns the value 10, so the output is 10.
Look at this code with a base class and a derived class:
class Animal {
public:
void speak() { std::cout << "Animal speaks" << std::endl; }
};
class Dog : public Animal {
public:
void speak() { std::cout << "Dog barks" << std::endl; }
};
int main() {
Dog dog;
dog.speak();
return 0;
}What will this program print?
#include <iostream> class Animal { public: void speak() { std::cout << "Animal speaks" << std::endl; } }; class Dog : public Animal { public: void speak() { std::cout << "Dog barks" << std::endl; } }; int main() { Dog dog; dog.speak(); return 0; }
Which class's speak method is called on the Dog object?
The Dog class overrides the speak method. Calling dog.speak() calls the Dog version, printing "Dog barks".
Consider this code using virtual functions:
class Base {
public:
virtual void show() { std::cout << "Base show" << std::endl; }
};
class Derived : public Base {
public:
void show() override { std::cout << "Derived show" << std::endl; }
};
int main() {
Base* ptr = new Derived();
ptr->show();
delete ptr;
return 0;
}What will this program print?
#include <iostream> class Base { public: virtual void show() { std::cout << "Base show" << std::endl; } }; class Derived : public Base { public: void show() override { std::cout << "Derived show" << std::endl; } }; int main() { Base* ptr = new Derived(); ptr->show(); delete ptr; return 0; }
Virtual functions allow the program to decide which method to call at runtime.
The pointer ptr is of type Base* but points to a Derived object. Because show is virtual, the Derived version is called, printing "Derived show".
Look at this abstract class example:
class Shape {
public:
virtual void draw() = 0; // pure virtual function
};
class Circle : public Shape {
public:
void draw() override { std::cout << "Drawing Circle" << std::endl; }
};
int main() {
Circle c;
c.draw();
return 0;
}What will this program print?
#include <iostream> class Shape { public: virtual void draw() = 0; // pure virtual function }; class Circle : public Shape { public: void draw() override { std::cout << "Drawing Circle" << std::endl; } }; int main() { Circle c; c.draw(); return 0; }
Can you create an object of the abstract class? What about the derived class?
The abstract class Shape cannot be instantiated, but Circle implements draw. Creating a Circle object and calling draw prints "Drawing Circle".
Consider this code:
class Logger {
public:
void log(const std::string& message) {
std::cout << "Log: " << message << std::endl;
}
};
class FileLogger : public Logger {
public:
void log(const std::string& message) {
// code to write message to a file
std::cout << "File log: " << message << std::endl;
}
};Which OOP principle does this best illustrate?
#include <iostream> #include <string> class Logger { public: void log(const std::string& message) { std::cout << "Log: " << message << std::endl; } }; class FileLogger : public Logger { public: void log(const std::string& message) { // code to write message to a file std::cout << "File log: " << message << std::endl; } };
Look at how FileLogger relates to Logger.
FileLogger inherits from Logger, reusing and extending its functionality. This is an example of inheritance.