4. Practical Applications
4.1 Complete Example: Drawing Application
#include <iostream>
#include <vector>
#include <string>
#include <cmath>
using namespace std;
// Abstract base class
class Shape {
protected:
string color;
double x, y; // Position
public:
Shape(string c, double px, double py) : color(c), x(px), y(py) {}
// Pure virtual functions
virtual double getArea() = 0;
virtual double getPerimeter() = 0;
virtual void draw() = 0;
virtual string getType() = 0;
// Concrete functions
void move(double dx, double dy) {
x += dx;
y += dy;
cout << getType() << " moved to (" << x << ", " << y << ")" << endl;
}
void setColor(string c) {
color = c;
cout << getType() << " color changed to " << color << endl;
}
string getColor() { return color; }
virtual void displayInfo() {
cout << getType() << " at (" << x << ", " << y << ")" << endl;
cout << "Color: " << color << endl;
cout << "Area: " << getArea() << endl;
cout << "Perimeter: " << getPerimeter() << endl;
}
virtual ~Shape() {}
};
class Circle : public Shape {
private:
double radius;
public:
Circle(string c, double px, double py, double r)
: Shape(c, px, py), radius(r) {}
double getArea() override {
return 3.14159 * radius * radius;
}
double getPerimeter() override {
return 2 * 3.14159 * radius;
}
void draw() override {
cout << "Drawing " << color << " circle at (" << x << ", " << y
<< ") with radius " << radius << endl;
}
string getType() override {
return "Circle";
}
void displayInfo() override {
Shape::displayInfo();
cout << "Radius: " << radius << endl;
}
};
class Rectangle : public Shape {
private:
double width, height;
public:
Rectangle(string c, double px, double py, double w, double h)
: Shape(c, px, py), width(w), height(h) {}
double getArea() override {
return width * height;
}
double getPerimeter() override {
return 2 * (width + height);
}
void draw() override {
cout << "Drawing " << color << " rectangle at (" << x << ", " << y
<< ") with width " << width << " and height " << height << endl;
}
string getType() override {
return "Rectangle";
}
void displayInfo() override {
Shape::displayInfo();
cout << "Width: " << width << ", Height: " << height << endl;
}
};
class Triangle : public Shape {
private:
double base, height;
public:
Triangle(string c, double px, double py, double b, double h)
: Shape(c, px, py), base(b), height(h) {}
double getArea() override {
return 0.5 * base * height;
}
double getPerimeter() override {
// Simplified: assumes isosceles triangle
double side = sqrt((base/2)*(base/2) + height*height);
return base + 2*side;
}
void draw() override {
cout << "Drawing " << color << " triangle at (" << x << ", " << y
<< ") with base " << base << " and height " << height << endl;
}
string getType() override {
return "Triangle";
}
void displayInfo() override {
Shape::displayInfo();
cout << "Base: " << base << ", Height: " << height << endl;
}
};
// Canvas class to manage shapes
class Canvas {
private:
vector<Shape*> shapes;
public:
void addShape(Shape* shape) {
shapes.push_back(shape);
cout << shape->getType() << " added to canvas" << endl;
}
void drawAll() {
cout << "\n=== Drawing All Shapes ===" << endl;
for (Shape* shape : shapes) {
shape->draw();
}
}
void displayAllInfo() {
cout << "\n=== All Shapes Information ===" << endl;
for (size_t i = 0; i < shapes.size(); i++) {
cout << "\nShape " << (i+1) << ":" << endl;
shapes[i]->displayInfo();
cout << "-----------------------------------" << endl;
}
}
double getTotalArea() {
double total = 0;
for (Shape* shape : shapes) {
total += shape->getArea();
}
return total;
}
void removeShape(int index) {
if (index >= 0 && index < shapes.size()) {
delete shapes[index];
shapes.erase(shapes.begin() + index);
cout << "Shape removed" << endl;
}
}
~Canvas() {
for (Shape* shape : shapes) {
delete shape;
}
}
};
int main() {
Canvas canvas;
cout << "=== Creating Shapes ===" << endl;
canvas.addShape(new Circle("Red", 10, 10, 5));
canvas.addShape(new Rectangle("Blue", 20, 20, 10, 8));
canvas.addShape(new Triangle("Green", 30, 30, 6, 4));
canvas.addShape(new Circle("Yellow", 40, 40, 7));
canvas.drawAll();
canvas.displayAllInfo();
cout << "\nTotal area of all shapes: " << canvas.getTotalArea() << endl;
return 0;
}
4.2 Example: Game Character System
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// Abstract base class
class GameCharacter {
protected:
string name;
int health;
int maxHealth;
int attackPower;
public:
GameCharacter(string n, int hp, int atk)
: name(n), health(hp), maxHealth(hp), attackPower(atk) {}
// Pure virtual functions
virtual void attack(GameCharacter* target) = 0;
virtual void specialAbility() = 0;
virtual string getClass() = 0;
// Concrete functions
void takeDamage(int damage) {
health -= damage;
if (health < 0) health = 0;
cout << name << " takes " << damage << " damage! Health: " << health << endl;
if (health == 0) {
cout << name << " has been defeated!" << endl;
}
}
void heal(int amount) {
health += amount;
if (health > maxHealth) health = maxHealth;
cout << name << " heals " << amount << " HP! Health: " << health << endl;
}
bool isAlive() {
return health > 0;
}
void displayStatus() {
cout << name << " (" << getClass() << ")" << endl;
cout << "Health: " << health << "/" << maxHealth << endl;
cout << "Attack Power: " << attackPower << endl;
}
string getName() { return name; }
int getAttackPower() { return attackPower; }
virtual ~GameCharacter() {}
};
class Warrior : public GameCharacter {
private:
int armor;
public:
Warrior(string n) : GameCharacter(n, 150, 25), armor(10) {}
void attack(GameCharacter* target) override {
cout << name << " swings sword at " << target->getName() << "!" << endl;
target->takeDamage(attackPower);
}
void specialAbility() override {
cout << name << " uses Shield Bash!" << endl;
cout << "Defense increased temporarily!" << endl;
armor += 5;
}
string getClass() override {
return "Warrior";
}
void takeDamage(int damage) {
int reducedDamage = damage - armor;
if (reducedDamage < 0) reducedDamage = 0;
cout << name << "'s armor blocks " << armor << " damage!" << endl;
GameCharacter::takeDamage(reducedDamage);
}
};
class Mage : public GameCharacter {
private:
int mana;
public:
Mage(string n) : GameCharacter(n, 80, 35), mana(100) {}
void attack(GameCharacter* target) override {
if (mana >= 10) {
cout << name << " casts Fireball at " << target->getName() << "!" << endl;
target->takeDamage(attackPower);
mana -= 10;
} else {
cout << name << " is out of mana!" << endl;
}
}
void specialAbility() override {
if (mana >= 30) {
cout << name << " casts Meteor Storm!" << endl;
cout << "Massive area damage!" << endl;
mana -= 30;
} else {
cout << name << " doesn't have enough mana!" << endl;
}
}
string getClass() override {
return "Mage";
}
void displayStatus() {
GameCharacter::displayStatus();
cout << "Mana: " << mana << endl;
}
};
class Archer : public GameCharacter {
private:
int arrows;
public:
Archer(string n) : GameCharacter(n, 100, 30), arrows(50) {}
void attack(GameCharacter* target) override {
if (arrows > 0) {
cout << name << " shoots arrow at " << target->getName() << "!" << endl;
target->takeDamage(attackPower);
arrows--;
} else {
cout << name << " is out of arrows!" << endl;
}
}
void specialAbility() override {
if (arrows >= 5) {
cout << name << " uses Multi-Shot!" << endl;
cout << "Fires multiple arrows!" << endl;
arrows -= 5;
} else {
cout << name << " doesn't have enough arrows!" << endl;
}
}
string getClass() override {
return "Archer";
}
void displayStatus() {
GameCharacter::displayStatus();
cout << "Arrows: " << arrows << endl;
}
};
int main() {
cout << "=== Character Creation ===" << endl;
vector<GameCharacter*> party;
party.push_back(new Warrior("Thorin"));
party.push_back(new Mage("Gandalf"));
party.push_back(new Archer("Legolas"));
cout << "\n=== Party Status ===" << endl;
for (GameCharacter* character : party) {
character->displayStatus();
cout << endl;
}
cout << "=== Battle Simulation ===" << endl;
GameCharacter* enemy = new Warrior("Orc");
cout << "\nEnemy appears: ";
enemy->displayStatus();
cout << "\n--- Round 1 ---" << endl;
party[0]->attack(enemy);
party[1]->attack(enemy);
party[2]->attack(enemy);
cout << "\n--- Round 2 ---" << endl;
party[0]->specialAbility();
party[1]->specialAbility();
party[2]->specialAbility();
// Cleanup
for (GameCharacter* character : party) {
delete character;
}
delete enemy;
return 0;
}
4.3 Best Practices
1. Always Use Virtual Destructors in Base Classes
class Base {
public:
virtual ~Base() {} // CRITICAL!
};
2. Use override Keyword
class Derived : public Base {
public:
void func() override { // Compiler checks
// implementation
}
};
3. Use Abstract Classes for Interfaces
class IDrawable {
public:
virtual void draw() = 0;
virtual ~IDrawable() {}
};
4. Prefer References or Pointers for Polymorphism
// GOOD: Using pointer or reference
void process(Shape* shape) {
shape->draw();
}
void process(Shape& shape) {
shape.draw();
}
// BAD: Pass by value causes slicing
void process(Shape shape) { // DON'T DO THIS
shape.draw();
}
5. Check for Null Pointers
Shape* shape = findShape(id);
if (shape != nullptr) {
shape->draw();
}
No comments to display
No comments to display