์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐ŸŽฏ C++ ๊ฐ์ฒด์ง€ํ–ฅ๊ณผ ๋‹คํ˜•์„ฑ, ๊ฐ€์ƒํ•จ์ˆ˜๋ถ€ํ„ฐ ์„ค๊ณ„ ํŒจํ„ด๊นŒ์ง€!

๐ŸŽฏ C++ ๊ฐ์ฒด์ง€ํ–ฅ๊ณผ ๋‹คํ˜•์„ฑ, ๊ฐ€์ƒํ•จ์ˆ˜๋ถ€ํ„ฐ ์„ค๊ณ„ ํŒจํ„ด๊นŒ์ง€!

์นœ๊ตฌ์ฒ˜๋Ÿผ ์‰ฝ๊ฒŒ ๋ฐฐ์šฐ๋Š” C++ ๊ณ ๊ธ‰ ๊ฐœ๋… ์™„์ „์ •๋ณต ๊ฐ€์ด๋“œ ๐Ÿš€
์•ผ, ์•ˆ๋…•! ๐Ÿ˜Š ์˜ค๋Š˜์€ C++์˜ ์ง„์งœ ๋งค๋ ฅ์ ์ธ ๋ถ€๋ถ„์„ ํŒŒํ—ค์ณ๋ณผ ๊ฑฐ์•ผ. ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ(OOP)์ด๋ผ๋Š” ๋ง ๋“ค์–ด๋ดค์ง€? ๊ทธ๋ƒฅ ํด๋ž˜์Šค ๋งŒ๋“ค๊ณ  ๊ฐ์ฒด ์ƒ์„ฑํ•˜๋Š” ๊ฒŒ ์ „๋ถ€๊ฐ€ ์•„๋‹ˆ์•ผ. ์ง„์งœ ํ•ต์‹ฌ์€ ๋‹คํ˜•์„ฑ(Polymorphism)์ด๋ผ๋Š” ๊ฐœ๋…์ธ๋ฐ, ์ด๊ฒŒ ์ •๋ง C++์„ ๊ฐ•๋ ฅํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋น„๋ฐ€ ๋ฌด๊ธฐ๊ฑฐ๋“ ! ๐ŸŽจ

์ด ๊ธ€์—์„œ๋Š” ๊ฐ€์ƒํ•จ์ˆ˜, ์ถ”์ƒํด๋ž˜์Šค, ๊ทธ๋ฆฌ๊ณ  ์‹ค๋ฌด์—์„œ ์ •๋ง ๋งŽ์ด ์“ฐ์ด๋Š” ๋””์ž์ธ ํŒจํ„ด๊นŒ์ง€ ์ „๋ถ€ ๋‹ค๋ฃฐ ๊ฑฐ์•ผ. ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ณต๋ถ€ํ•˜๋ฉด์„œ ๋ง‰๋ง‰ํ–ˆ๋˜ ๋ถ€๋ถ„๋“ค, ์ด์ œ ์‹œ์›ํ•˜๊ฒŒ ํ’€์–ด๋ณด์ž! ๐Ÿ’ช

๐ŸŽช ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•ต์‹ฌ, ๋‹คํ˜•์„ฑ์ด๋ž€?

๋‹คํ˜•์„ฑ์ด๋ผ๋Š” ๋‹จ์–ด ์ž์ฒด๊ฐ€ ์ข€ ์–ด๋ ต๊ฒŒ ๋А๊ปด์ง€์ง€? ๊ทผ๋ฐ ์‚ฌ์‹ค ๊ฐœ๋…์€ ์—„์ฒญ ์ง๊ด€์ ์ด์•ผ. "๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋‹ค๋ฅธ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•œ๋‹ค"๋Š” ๊ฒŒ ํ•ต์‹ฌ์ด๊ฑฐ๋“ .

์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊ฒŒ. ๋„ˆ๊ฐ€ ๋™๋ฌผ์› ๊ด€๋ฆฌ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ด. ๐Ÿฆ๐Ÿถ๐Ÿฑ

class Animal {
public:
    void makeSound() {
        cout << "๋™๋ฌผ ์†Œ๋ฆฌ!" << endl;
    }
};

class Dog : public Animal {
public:
    void makeSound() {
        cout << "๋ฉ๋ฉ!" << endl;
    }
};

class Cat : public Animal {
public:
    void makeSound() {
        cout << "์•ผ์˜น!" << endl;
    }
};
์ด๋ ‡๊ฒŒ ์ฝ”๋“œ๋ฅผ ์งฐ๋‹ค๋ฉด, ๊ฐ ๋™๋ฌผ๋งˆ๋‹ค ๋‹ค๋ฅธ ์†Œ๋ฆฌ๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ์–ด. ๊ทผ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์–ด! ๐Ÿ˜ฑ

Animal* animal = new Dog();
animal->makeSound();  // ๊ฒฐ๊ณผ: "๋™๋ฌผ ์†Œ๋ฆฌ!" (์–ด? ๋ฉ๋ฉ์ด ์•„๋‹ˆ๋„ค?)
์™œ ์ด๋Ÿฐ ์ผ์ด ๋ฒŒ์–ด์งˆ๊นŒ? ๋ฐ”๋กœ ์ •์  ๋ฐ”์ธ๋”ฉ(Static Binding) ๋•Œ๋ฌธ์ด์•ผ. ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํฌ์ธํ„ฐ์˜ ํƒ€์ž…(Animal*)๋งŒ ๋ณด๊ณ  ์–ด๋–ค ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ• ์ง€ ๊ฒฐ์ •ํ•ด๋ฒ„๋ฆฌ๊ฑฐ๋“ .

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒŒ ๋ฐ”๋กœ ๊ฐ€์ƒํ•จ์ˆ˜(Virtual Function)์•ผ! ๐ŸŽฏ
๋‹คํ˜•์„ฑ์˜ ์ž‘๋™ ์›๋ฆฌ Animal ํด๋ž˜์Šค virtual makeSound() ๊ธฐ๋ณธ ๋™๋ฌผ ์†Œ๋ฆฌ Dog ํด๋ž˜์Šค makeSound() override ๋ฉ๋ฉ! Cat ํด๋ž˜์Šค makeSound() override ์•ผ์˜น! ๋Ÿฐํƒ€์ž„ ๋‹คํ˜•์„ฑ ์‹คํ–‰ ์‹œ์ ์— ์‹ค์ œ ๊ฐ์ฒด ํƒ€์ž…์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ํ•จ์ˆ˜ ํ˜ธ์ถœ!

๐Ÿ”ฎ ๊ฐ€์ƒํ•จ์ˆ˜(Virtual Function)์˜ ๋งˆ๋ฒ•

์ž, ์ด์ œ ์ง„์งœ ๋งˆ๋ฒ•์„ ๋ถ€๋ ค๋ณผ ์‹œ๊ฐ„์ด์•ผ! โœจ ๊ฐ€์ƒํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•„๊นŒ ๊ทธ ๋ฌธ์ œ๊ฐ€ ๊น”๋”ํ•˜๊ฒŒ ํ•ด๊ฒฐ๋ผ.

class Animal {
public:
    virtual void makeSound() {  // virtual ํ‚ค์›Œ๋“œ ์ถ”๊ฐ€!
        cout << "๋™๋ฌผ ์†Œ๋ฆฌ!" << endl;
    }
    
    virtual ~Animal() {}  // ๊ฐ€์ƒ ์†Œ๋ฉธ์ž๋„ ์ค‘์š”ํ•ด!
};

class Dog : public Animal {
public:
    void makeSound() override {  // override ํ‚ค์›Œ๋“œ๋กœ ๋ช…ํ™•ํ•˜๊ฒŒ!
        cout << "๋ฉ๋ฉ!" << endl;
    }
};

class Cat : public Animal {
public:
    void makeSound() override {
        cout << "์•ผ์˜น!" << endl;
    }
};
์ด์ œ ๋‹ค์‹œ ํ…Œ์ŠคํŠธํ•ด๋ณด๋ฉด?

Animal* animal1 = new Dog();
Animal* animal2 = new Cat();

animal1->makeSound();  // ๊ฒฐ๊ณผ: "๋ฉ๋ฉ!" ๐ŸŽ‰
animal2->makeSound();  // ๊ฒฐ๊ณผ: "์•ผ์˜น!" ๐ŸŽŠ

delete animal1;
delete animal2;
์™„๋ฒฝํ•˜๊ฒŒ ์ž‘๋™ํ•ด! ์ด๊ฒŒ ๋ฐ”๋กœ ๋™์  ๋ฐ”์ธ๋”ฉ(Dynamic Binding)์ด์•ผ. ์‹คํ–‰ ์‹œ์ ์— ์‹ค์ œ ๊ฐ์ฒด์˜ ํƒ€์ž…์„ ํ™•์ธํ•ด์„œ ์ ์ ˆํ•œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฑฐ์ง€. ๐ŸŽฏ

๐Ÿ’ก ํ•ต์‹ฌ ํฌ์ธํŠธ!

virtual ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ด๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ vtable(๊ฐ€์ƒ ํ•จ์ˆ˜ ํ…Œ์ด๋ธ”)์ด๋ผ๋Š” ๊ฑธ ๋งŒ๋“ค์–ด. ์ด ํ…Œ์ด๋ธ”์—๋Š” ๊ฐ ํด๋ž˜์Šค์˜ ๊ฐ€์ƒํ•จ์ˆ˜ ์ฃผ์†Œ๊ฐ€ ์ €์žฅ๋˜์–ด ์žˆ๊ณ , ๋Ÿฐํƒ€์ž„์— ์ด ํ…Œ์ด๋ธ”์„ ์ฐธ์กฐํ•ด์„œ ์˜ฌ๋ฐ”๋ฅธ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฑฐ์•ผ! ๐Ÿ—‚๏ธ

๐ŸŽ“ ๊ฐ€์ƒํ•จ์ˆ˜ ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์‚ฌํ•ญ

์ž, ๊ฐ€์ƒํ•จ์ˆ˜๋ฅผ ์“ธ ๋•Œ ๊ผญ ์•Œ์•„์•ผ ํ•  ๊ฒƒ๋“ค์ด ์žˆ์–ด:

1๏ธโƒฃ ๊ฐ€์ƒ ์†Œ๋ฉธ์ž๋Š” ํ•„์ˆ˜!

class Base {
public:
    virtual ~Base() {  // ์ด๊ฑฐ ์—†์œผ๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐœ์ƒ!
        cout << "Base ์†Œ๋ฉธ์ž" << endl;
    }
};

class Derived : public Base {
private:
    int* data;
public:
    Derived() { data = new int[100]; }
    ~Derived() {
        delete[] data;  // ์ด๊ฒŒ ํ˜ธ์ถœ ์•ˆ ๋˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜!
        cout << "Derived ์†Œ๋ฉธ์ž" << endl;
    }
};
๋งŒ์•ฝ Base์˜ ์†Œ๋ฉธ์ž๊ฐ€ ๊ฐ€์ƒํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ฉด, Base* ptr = new Derived(); ํ›„์— delete ptr;์„ ํ•ด๋„ Derived์˜ ์†Œ๋ฉธ์ž๊ฐ€ ํ˜ธ์ถœ ์•ˆ ๋ผ! ๐Ÿ˜ฑ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜์˜ ์ฃผ๋ฒ”์ด์ง€.

2๏ธโƒฃ override ํ‚ค์›Œ๋“œ ํ™œ์šฉํ•˜๊ธฐ

C++11๋ถ€ํ„ฐ override ํ‚ค์›Œ๋“œ๊ฐ€ ์ถ”๊ฐ€๋์–ด. ์ด๊ฑฐ ์ง„์งœ ์œ ์šฉํ•ด!

class Animal {
public:
    virtual void makeSound() const { }
};

class Dog : public Animal {
public:
    // ์‹ค์ˆ˜๋กœ const๋ฅผ ๋นผ๋จน์—ˆ๋‹ค๋ฉด?
    void makeSound() override {  // ์ปดํŒŒ์ผ ์—๋Ÿฌ ๋ฐœ์ƒ! ๐Ÿ‘
        cout << "๋ฉ๋ฉ!" << endl;
    }
};
override๋ฅผ ๋ถ™์ด๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ "์ด ํ•จ์ˆ˜๊ฐ€ ์ •๋ง ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๊ฐ€์ƒํ•จ์ˆ˜๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œํ•˜๋Š”์ง€" ์ฒดํฌํ•ด์ค˜. ์‹ค์ˆ˜๋ฅผ ๋ฏธ๋ฆฌ ์žก์•„์ฃผ๋Š” ๊ฑฐ์ง€! ๐Ÿ›ก๏ธ

3๏ธโƒฃ final ํ‚ค์›Œ๋“œ๋กœ ์˜ค๋ฒ„๋ผ์ด๋“œ ๋ฐฉ์ง€

class Animal {
public:
    virtual void makeSound() { }
};

class Dog : public Animal {
public:
    void makeSound() final {  // ๋” ์ด์ƒ ์˜ค๋ฒ„๋ผ์ด๋“œ ๋ถˆ๊ฐ€!
        cout << "๋ฉ๋ฉ!" << endl;
    }
};

class Puppy : public Dog {
public:
    void makeSound() { }  // ์ปดํŒŒ์ผ ์—๋Ÿฌ!
};
ํŠน์ • ํ•จ์ˆ˜๋ฅผ ๋” ์ด์ƒ ์˜ค๋ฒ„๋ผ์ด๋“œํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ๋ง‰๊ณ  ์‹ถ์„ ๋•Œ final์„ ์‚ฌ์šฉํ•ด! ๐Ÿšซ

๐Ÿ›๏ธ ์ˆœ์ˆ˜ ๊ฐ€์ƒํ•จ์ˆ˜์™€ ์ถ”์ƒํด๋ž˜์Šค

์ด์ œ ์ข€ ๋” ๊ณ ๊ธ‰ ๊ฐœ๋…์œผ๋กœ ๋“ค์–ด๊ฐ€๋ณผ๊นŒ? ๐Ÿ˜Ž ๋•Œ๋กœ๋Š” ๋ถ€๋ชจ ํด๋ž˜์Šค์—์„œ ํ•จ์ˆ˜์˜ ๊ตฌํ˜„์„ ์•„์˜ˆ ์ œ๊ณตํ•˜์ง€ ์•Š๊ณ , "์ž์‹ ํด๋ž˜์Šค์—์„œ ๋ฐ˜๋“œ์‹œ ๊ตฌํ˜„ํ•˜๋ผ!"๊ณ  ๊ฐ•์ œํ•˜๊ณ  ์‹ถ์„ ๋•Œ๊ฐ€ ์žˆ์–ด. ์ด๋Ÿด ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ์ˆœ์ˆ˜ ๊ฐ€์ƒํ•จ์ˆ˜(Pure Virtual Function)์•ผ!

class Shape {
public:
    // = 0์„ ๋ถ™์ด๋ฉด ์ˆœ์ˆ˜ ๊ฐ€์ƒํ•จ์ˆ˜!
    virtual double getArea() const = 0;
    virtual void draw() const = 0;
    
    virtual ~Shape() {}
};
์ˆœ์ˆ˜ ๊ฐ€์ƒํ•จ์ˆ˜๋ฅผ ํ•˜๋‚˜๋ผ๋„ ๊ฐ€์ง„ ํด๋ž˜์Šค๋Š” ์ถ”์ƒํด๋ž˜์Šค(Abstract Class)๊ฐ€ ๋ผ. ์ถ”์ƒํด๋ž˜์Šค๋Š” ์ง์ ‘ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์—†์–ด! ๐Ÿšซ

Shape shape;  // ์ปดํŒŒ์ผ ์—๋Ÿฌ! ์ถ”์ƒํด๋ž˜์Šค๋Š” ์ธ์Šคํ„ด์Šคํ™” ๋ถˆ๊ฐ€
Shape* ptr = new Shape();  // ์ด๊ฒƒ๋„ ์—๋Ÿฌ!
๋Œ€์‹  ์ถ”์ƒํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์€ ์ž์‹ ํด๋ž˜์Šค์—์„œ ๋ชจ๋“  ์ˆœ์ˆ˜ ๊ฐ€์ƒํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด.

class Circle : public Shape {
private:
    double radius;
    
public:
    Circle(double r) : radius(r) {}
    
    double getArea() const override {
        return 3.14159 * radius * radius;
    }
    
    void draw() const override {
        cout << "์›์„ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค. ๋ฐ˜์ง€๋ฆ„: " << radius << endl;
    }
};

class Rectangle : public Shape {
private:
    double width, height;
    
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    
    double getArea() const override {
        return width * height;
    }
    
    void draw() const override {
        cout << "์‚ฌ๊ฐํ˜•์„ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค. " << width << "x" << height << endl;
    }
};
์ด์ œ ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด! ๐ŸŽจ

vector<Shape*> shapes;
shapes.push_back(new Circle(5.0));
shapes.push_back(new Rectangle(4.0, 6.0));
shapes.push_back(new Circle(3.0));

for (Shape* shape : shapes) {
    shape->draw();
    cout << "๋ฉด์ : " << shape->getArea() << endl;
}

// ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ๋„ ์žŠ์ง€ ๋ง์ž!
for (Shape* shape : shapes) {
    delete shape;
}
shapes.clear();
๐Ÿค” ์™œ ์ถ”์ƒํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ• ๊นŒ?

์ถ”์ƒํด๋ž˜์Šค๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•˜๋Š” ์—ญํ• ์„ ํ•ด. "์ด ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์œผ๋ฉด ์ด๋Ÿฐ ๊ธฐ๋Šฅ๋“ค์„ ๋ฐ˜๋“œ์‹œ ๊ตฌํ˜„ํ•ด์•ผ ํ•ด!"๋ผ๊ณ  ๊ฐ•์ œํ•˜๋Š” ๊ฑฐ์ง€. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ฝ”๋“œ์˜ ์ผ๊ด€์„ฑ์ด ์œ ์ง€๋˜๊ณ , ์‹ค์ˆ˜๋กœ ์ค‘์š”ํ•œ ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ ์•ˆ ํ•˜๋Š” ๊ฑธ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์–ด! ๐Ÿ›ก๏ธ

๐ŸŽฏ ์ธํ„ฐํŽ˜์ด์Šค ํด๋ž˜์Šค ํŒจํ„ด

C++์—๋Š” Java๋‚˜ C#์ฒ˜๋Ÿผ interface ํ‚ค์›Œ๋“œ๊ฐ€ ์—†์–ด. ํ•˜์ง€๋งŒ ์ˆœ์ˆ˜ ๊ฐ€์ƒํ•จ์ˆ˜๋งŒ์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ์ถ”์ƒํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๋ฉด ์ธํ„ฐํŽ˜์ด์Šค์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€!

// ์ธํ„ฐํŽ˜์ด์Šค ์—ญํ• ์„ ํ•˜๋Š” ์ถ”์ƒํด๋ž˜์Šค
class IDrawable {
public:
    virtual void draw() const = 0;
    virtual ~IDrawable() {}
};

class IPrintable {
public:
    virtual void print() const = 0;
    virtual ~IPrintable() {}
};

// ๋‹ค์ค‘ ์ƒ์†์œผ๋กœ ์—ฌ๋Ÿฌ ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„
class Document : public IDrawable, public IPrintable {
private:
    string content;
    
public:
    Document(const string& c) : content(c) {}
    
    void draw() const override {
        cout << "๋ฌธ์„œ๋ฅผ ํ™”๋ฉด์— ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค." << endl;
    }
    
    void print() const override {
        cout << "๋ฌธ์„œ๋ฅผ ํ”„๋ฆฐํ„ฐ๋กœ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค: " << content << endl;
    }
};
์ด๋Ÿฐ ์‹์œผ๋กœ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•˜๋ฉด ํด๋ž˜์Šค ์„ค๊ณ„๊ฐ€ ํ›จ์”ฌ ๊น”๋”ํ•ด์ ธ! ๋ณดํ†ต ์ธํ„ฐํŽ˜์ด์Šค ํด๋ž˜์Šค ์ด๋ฆ„ ์•ž์— 'I'๋ฅผ ๋ถ™์ด๋Š” ๊ฒŒ ๊ด€๋ก€์•ผ. ๐Ÿ“
์ถ”์ƒํด๋ž˜์Šค ์ƒ์† ๊ตฌ์กฐ Shape (์ถ”์ƒํด๋ž˜์Šค) virtual getArea() = 0 virtual draw() = 0 Circle getArea() ๊ตฌํ˜„ draw() ๊ตฌํ˜„ ์ธ์Šคํ„ด์Šคํ™” ๊ฐ€๋Šฅ โœ“ Rectangle getArea() ๊ตฌํ˜„ draw() ๊ตฌํ˜„ ์ธ์Šคํ„ด์Šคํ™” ๊ฐ€๋Šฅ โœ“ Triangle getArea() ๊ตฌํ˜„ draw() ๊ตฌํ˜„ ์ธ์Šคํ„ด์Šคํ™” ๊ฐ€๋Šฅ โœ“ ๋‹คํ˜•์„ฑ์˜ ํž˜! Shape* ํฌ์ธํ„ฐ๋กœ ๋ชจ๋“  ๋„ํ˜•์„ ํ†ต์ผ๋œ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ

๐ŸŽจ ์‹ค์ „ ์˜ˆ์ œ: ๊ฒŒ์ž„ ์บ๋ฆญํ„ฐ ์‹œ์Šคํ…œ

์ด๋ก ๋งŒ ๋ฐฐ์šฐ๋ฉด ์žฌ๋ฏธ์—†์ž–์•„? ๐Ÿ˜… ์‹ค์ œ๋กœ ๊ฒŒ์ž„ ๊ฐœ๋ฐœ์—์„œ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ์บ๋ฆญํ„ฐ ์‹œ์Šคํ…œ์„ ๋งŒ๋“ค์–ด๋ณด์ž! ์ด ์˜ˆ์ œ๋Š” ์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•  ๋•Œ๋„ ์ •๋ง ์œ ์šฉํ•œ ํŒจํ„ด์ด์•ผ. ๐ŸŽฎ

// ์ถ”์ƒ ๊ธฐ๋ณธ ํด๋ž˜์Šค
class GameCharacter {
protected:
    string name;
    int health;
    int attackPower;
    
public:
    GameCharacter(const string& n, int hp, int atk) 
        : name(n), health(hp), attackPower(atk) {}
    
    virtual ~GameCharacter() {}
    
    // ์ˆœ์ˆ˜ ๊ฐ€์ƒํ•จ์ˆ˜๋“ค
    virtual void attack() = 0;
    virtual void defend() = 0;
    virtual void useSpecialSkill() = 0;
    
    // ์ผ๋ฐ˜ ๊ฐ€์ƒํ•จ์ˆ˜ (๊ธฐ๋ณธ ๊ตฌํ˜„ ์ œ๊ณต)
    virtual void takeDamage(int damage) {
        health -= damage;
        if (health < 0) health = 0;
        cout << name << "์ด(๊ฐ€) " << damage << " ๋ฐ๋ฏธ์ง€๋ฅผ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค! ";
        cout << "๋‚จ์€ ์ฒด๋ ฅ: " << health << endl;
    }
    
    // ์ผ๋ฐ˜ ๋ฉค๋ฒ„ ํ•จ์ˆ˜
    bool isAlive() const { return health > 0; }
    string getName() const { return name; }
    int getHealth() const { return health; }
};

// ์ „์‚ฌ ํด๋ž˜์Šค
class Warrior : public GameCharacter {
private:
    int armor;
    
public:
    Warrior(const string& n) 
        : GameCharacter(n, 150, 30), armor(20) {}
    
    void attack() override {
        cout << name << "์ด(๊ฐ€) ๊ฐ•๋ ฅํ•œ ๊ฒ€ ๊ณต๊ฒฉ์„ ํ•ฉ๋‹ˆ๋‹ค! ๐Ÿ’ช" << endl;
        cout << "๊ณต๊ฒฉ๋ ฅ: " << attackPower << endl;
    }
    
    void defend() override {
        cout << name << "์ด(๊ฐ€) ๋ฐฉํŒจ๋กœ ๋ฐฉ์–ดํ•ฉ๋‹ˆ๋‹ค! ๐Ÿ›ก๏ธ" << endl;
        cout << "๋ฐฉ์–ด๋ ฅ: " << armor << endl;
    }
    
    void useSpecialSkill() override {
        cout << name << "์˜ ํŠน์ˆ˜ ์Šคํ‚ฌ: ๊ด‘์ „์‚ฌ์˜ ๋ถ„๋…ธ! โš”๏ธ" << endl;
        cout << "๊ณต๊ฒฉ๋ ฅ์ด 2๋ฐฐ๋กœ ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค!" << endl;
    }
    
    void takeDamage(int damage) override {
        int actualDamage = damage - armor;
        if (actualDamage < 0) actualDamage = 0;
        GameCharacter::takeDamage(actualDamage);
    }
};

// ๋งˆ๋ฒ•์‚ฌ ํด๋ž˜์Šค
class Mage : public GameCharacter {
private:
    int mana;
    
public:
    Mage(const string& n) 
        : GameCharacter(n, 80, 50), mana(100) {}
    
    void attack() override {
        if (mana >= 10) {
            cout << name << "์ด(๊ฐ€) ํŒŒ์ด์–ด๋ณผ์„ ์‹œ์ „ํ•ฉ๋‹ˆ๋‹ค! ๐Ÿ”ฅ" << endl;
            cout << "๋งˆ๋ฒ• ๊ณต๊ฒฉ๋ ฅ: " << attackPower << endl;
            mana -= 10;
        } else {
            cout << "๋งˆ๋‚˜๊ฐ€ ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค!" << endl;
        }
    }
    
    void defend() override {
        cout << name << "์ด(๊ฐ€) ๋งˆ๋ฒ• ๋ณดํ˜ธ๋ง‰์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค! โœจ" << endl;
        mana -= 5;
    }
    
    void useSpecialSkill() override {
        if (mana >= 50) {
            cout << name << "์˜ ํŠน์ˆ˜ ์Šคํ‚ฌ: ๋ฉ”ํ…Œ์˜ค! โ˜„๏ธ" << endl;
            cout << "๊ด‘์—ญ ๋งˆ๋ฒ• ๊ณต๊ฒฉ!" << endl;
            mana -= 50;
        } else {
            cout << "๋งˆ๋‚˜๊ฐ€ ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค!" << endl;
        }
    }
};

// ๊ถ์ˆ˜ ํด๋ž˜์Šค
class Archer : public GameCharacter {
private:
    int arrows;
    
public:
    Archer(const string& n) 
        : GameCharacter(n, 100, 40), arrows(30) {}
    
    void attack() override {
        if (arrows > 0) {
            cout << name << "์ด(๊ฐ€) ํ™”์‚ด์„ ๋ฐœ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๐Ÿน" << endl;
            cout << "๊ณต๊ฒฉ๋ ฅ: " << attackPower << endl;
            arrows--;
        } else {
            cout << "ํ™”์‚ด์ด ๋–จ์–ด์กŒ์Šต๋‹ˆ๋‹ค!" << endl;
        }
    }
    
    void defend() override {
        cout << name << "์ด(๊ฐ€) ์žฌ๋น ๋ฅด๊ฒŒ ํšŒํ”ผํ•ฉ๋‹ˆ๋‹ค! ๐Ÿ’จ" << endl;
    }
    
    void useSpecialSkill() override {
        if (arrows >= 5) {
            cout << name << "์˜ ํŠน์ˆ˜ ์Šคํ‚ฌ: ์—ฐ์† ์‚ฌ๊ฒฉ! ๐ŸŽฏ" << endl;
            cout << "5๋ฐœ์˜ ํ™”์‚ด์„ ๋™์‹œ์— ๋ฐœ์‚ฌ!" << endl;
            arrows -= 5;
        } else {
            cout << "ํ™”์‚ด์ด ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค!" << endl;
        }
    }
};
์ด์ œ ์ด ์บ๋ฆญํ„ฐ๋“ค์„ ์‚ฌ์šฉํ•ด๋ณด์ž! ๐ŸŽฎ

int main() {
    // ๋‹ค์–‘ํ•œ ์บ๋ฆญํ„ฐ ์ƒ์„ฑ
    vector<GameCharacter*> party;
    party.push_back(new Warrior("๊ทธ๋กฌ"));
    party.push_back(new Mage("์—˜๋ฆฌ๋‚˜"));
    party.push_back(new Archer("๋ ˆ๊ณ ๋ผ์Šค"));
    
    cout << "=== ํŒŒํ‹ฐ์› ์†Œ๊ฐœ ===" << endl;
    for (auto character : party) {
        cout << character->getName() << " (์ฒด๋ ฅ: " 
             << character->getHealth() << ")" << endl;
    }
    
    cout << "\n=== ์ „ํˆฌ ์‹œ์ž‘! ===" << endl;
    
    // ๋‹คํ˜•์„ฑ์˜ ํž˜! ๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋‹ค๋ฅธ ๋™์ž‘
    for (auto character : party) {
        character->attack();
        character->useSpecialSkill();
        cout << endl;
    }
    
    cout << "=== ์ ์˜ ๊ณต๊ฒฉ! ===" << endl;
    for (auto character : party) {
        character->takeDamage(25);
    }
    
    // ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ
    for (auto character : party) {
        delete character;
    }
    party.clear();
    
    return 0;
}
๐ŸŽฏ ์ด ์˜ˆ์ œ์˜ ํ•ต์‹ฌ ํฌ์ธํŠธ!

1๏ธโƒฃ GameCharacter* ํฌ์ธํ„ฐ ํ•˜๋‚˜๋กœ ๋ชจ๋“  ์บ๋ฆญํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด!
2๏ธโƒฃ ์ƒˆ๋กœ์šด ์บ๋ฆญํ„ฐ ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•ด๋„ ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•  ํ•„์š”๊ฐ€ ์—†์–ด!
3๏ธโƒฃ ๊ฐ ์บ๋ฆญํ„ฐ๋Š” ์ž์‹ ๋งŒ์˜ ํŠน์„ฑ์„ ์œ ์ง€ํ•˜๋ฉด์„œ๋„ ํ†ต์ผ๋œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ด!

์ด๊ฒŒ ๋ฐ”๋กœ ๊ฐœ๋ฐฉ-ํ์‡„ ์›์น™(Open-Closed Principle)์ด์•ผ! ํ™•์žฅ์—๋Š” ์—ด๋ ค์žˆ๊ณ , ์ˆ˜์ •์—๋Š” ๋‹ซํ˜€์žˆ๋Š” ์„ค๊ณ„! ๐Ÿ†

๐Ÿ—๏ธ ๋””์ž์ธ ํŒจํ„ด: ์‹ค๋ฌด์—์„œ ๋ฐ”๋กœ ์“ฐ๋Š” ์„ค๊ณ„ ๊ธฐ๋ฒ•

์ž, ์ด์ œ ์ง„์งœ ์‹ค๋ฌด ์ด์•ผ๊ธฐ๋ฅผ ํ•ด๋ณผ๊นŒ? ๐Ÿ˜Ž ๋””์ž์ธ ํŒจํ„ด์€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋“ค์— ๋Œ€ํ•œ ๊ฒ€์ฆ๋œ ํ•ด๊ฒฐ์ฑ…์ด์•ผ. ์„ ๋ฐฐ ๊ฐœ๋ฐœ์ž๋“ค์ด ์ˆ˜์‹ญ ๋…„๊ฐ„ ์Œ“์•„์˜จ ๋…ธํ•˜์šฐ๋ฅผ ํŒจํ„ดํ™”ํ•œ ๊ฑฐ์ง€!

C++์—์„œ ๊ฐ์ฒด์ง€ํ–ฅ๊ณผ ๋‹คํ˜•์„ฑ์„ ํ™œ์šฉํ•œ ๋Œ€ํ‘œ์ ์ธ ๋””์ž์ธ ํŒจํ„ด๋“ค์„ ์•Œ์•„๋ณด์ž! ๐ŸŽจ

1๏ธโƒฃ ํŒฉํ† ๋ฆฌ ํŒจํ„ด (Factory Pattern)

๊ฐ์ฒด ์ƒ์„ฑ์„ ์ „๋‹ดํ•˜๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“œ๋Š” ํŒจํ„ด์ด์•ผ. ๊ฐ์ฒด ์ƒ์„ฑ ๋กœ์ง์ด ๋ณต์žกํ•˜๊ฑฐ๋‚˜, ์–ด๋–ค ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค์ง€ ๋Ÿฐํƒ€์ž„์— ๊ฒฐ์ •ํ•ด์•ผ ํ•  ๋•Œ ์œ ์šฉํ•ด! ๐Ÿญ

// ์•ž์—์„œ ๋งŒ๋“  GameCharacter ํด๋ž˜์Šค๋“ค์„ ํ™œ์šฉ
class CharacterFactory {
public:
    enum CharacterType {
        WARRIOR,
        MAGE,
        ARCHER
    };
    
    static GameCharacter* createCharacter(CharacterType type, const string& name) {
        switch(type) {
            case WARRIOR:
                return new Warrior(name);
            case MAGE:
                return new Mage(name);
            case ARCHER:
                return new Archer(name);
            default:
                return nullptr;
        }
    }
};

// ์‚ฌ์šฉ ์˜ˆ์‹œ
int main() {
    // ํŒฉํ† ๋ฆฌ๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด ์ƒ์„ฑ
    GameCharacter* char1 = CharacterFactory::createCharacter(
        CharacterFactory::WARRIOR, "์•„์„œ์Šค"
    );
    
    GameCharacter* char2 = CharacterFactory::createCharacter(
        CharacterFactory::MAGE, "์ œ์ด๋‚˜"
    );
    
    char1->attack();
    char2->attack();
    
    delete char1;
    delete char2;
    
    return 0;
}
ํŒฉํ† ๋ฆฌ ํŒจํ„ด์˜ ์žฅ์ :
โœ… ๊ฐ์ฒด ์ƒ์„ฑ ๋กœ์ง์„ ํ•œ ๊ณณ์— ์ง‘์ค‘์‹œํ‚ฌ ์ˆ˜ ์žˆ์–ด
โœ… ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๊ฐ€ ๊ตฌ์ฒด์ ์ธ ํด๋ž˜์Šค์— ์˜์กดํ•˜์ง€ ์•Š์•„
โœ… ์ƒˆ๋กœ์šด ํƒ€์ž…์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์‰ฌ์›Œ
โœ… ๊ฐ์ฒด ์ƒ์„ฑ ๊ณผ์ •์ด ๋ณต์žกํ•ด๋„ ํด๋ผ์ด์–ธํŠธ๋Š” ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ!

2๏ธโƒฃ ์ „๋žต ํŒจํ„ด (Strategy Pattern)

์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์บก์Аํ™”ํ•ด์„œ ๋Ÿฐํƒ€์ž„์— ๊ต์ฒดํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“œ๋Š” ํŒจํ„ด์ด์•ผ. ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์ด ์žˆ์„ ๋•Œ ์œ ์šฉํ•ด! ๐ŸŽฏ

// ๊ณต๊ฒฉ ์ „๋žต ์ธํ„ฐํŽ˜์ด์Šค
class AttackStrategy {
public:
    virtual ~AttackStrategy() {}
    virtual void execute() = 0;
};

// ๊ตฌ์ฒด์ ์ธ ์ „๋žต๋“ค
class MeleeAttack : public AttackStrategy {
public:
    void execute() override {
        cout << "๊ทผ์ ‘ ๊ณต๊ฒฉ! ๊ฒ€์œผ๋กœ ๋ฒ ๊ธฐ! โš”๏ธ" << endl;
    }
};

class RangedAttack : public AttackStrategy {
public:
    void execute() override {
        cout << "์›๊ฑฐ๋ฆฌ ๊ณต๊ฒฉ! ํ™”์‚ด ๋ฐœ์‚ฌ! ๐Ÿน" << endl;
    }
};

class MagicAttack : public AttackStrategy {
public:
    void execute() override {
        cout << "๋งˆ๋ฒ• ๊ณต๊ฒฉ! ํŒŒ์ด์–ด๋ณผ! ๐Ÿ”ฅ" << endl;
    }
};

// ์ „๋žต์„ ์‚ฌ์šฉํ•˜๋Š” ์บ๋ฆญํ„ฐ
class StrategicCharacter {
private:
    string name;
    AttackStrategy* strategy;
    
public:
    StrategicCharacter(const string& n) : name(n), strategy(nullptr) {}
    
    ~StrategicCharacter() {
        if (strategy) delete strategy;
    }
    
    void setAttackStrategy(AttackStrategy* newStrategy) {
        if (strategy) delete strategy;
        strategy = newStrategy;
    }
    
    void performAttack() {
        if (strategy) {
            cout << name << "์˜ ๊ณต๊ฒฉ: ";
            strategy->execute();
        } else {
            cout << "๊ณต๊ฒฉ ์ „๋žต์ด ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค!" << endl;
        }
    }
};

// ์‚ฌ์šฉ ์˜ˆ์‹œ
int main() {
    StrategicCharacter hero("์šฉ์‚ฌ");
    
    // ์ƒํ™ฉ์— ๋”ฐ๋ผ ์ „๋žต ๋ณ€๊ฒฝ
    cout << "=== 1๋‹จ๊ณ„: ๊ทผ์ ‘ ์ „ํˆฌ ===" << endl;
    hero.setAttackStrategy(new MeleeAttack());
    hero.performAttack();
    
    cout << "\n=== 2๋‹จ๊ณ„: ์›๊ฑฐ๋ฆฌ ์ „ํˆฌ ===" << endl;
    hero.setAttackStrategy(new RangedAttack());
    hero.performAttack();
    
    cout << "\n=== 3๋‹จ๊ณ„: ๋งˆ๋ฒ• ์ „ํˆฌ ===" << endl;
    hero.setAttackStrategy(new MagicAttack());
    hero.performAttack();
    
    return 0;
}
์ „๋žต ํŒจํ„ด์€ ์ •๋ง ์œ ์šฉํ•ด! ํŠนํžˆ ๊ฒŒ์ž„์ด๋‚˜ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ํ”„๋กœ๊ทธ๋žจ์—์„œ AI ํ–‰๋™์„ ๊ตฌํ˜„ํ•  ๋•Œ ๋งŽ์ด ์จ. ๐Ÿค–

3๏ธโƒฃ ์˜ต์ €๋ฒ„ ํŒจํ„ด (Observer Pattern)

ํ•œ ๊ฐ์ฒด์˜ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ๊ทธ๊ฒƒ์— ์˜์กดํ•˜๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด๋“ค์—๊ฒŒ ์ž๋™์œผ๋กœ ์•Œ๋ ค์ฃผ๋Š” ํŒจํ„ด์ด์•ผ. ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ์‹œ์Šคํ…œ์—์„œ ์ •๋ง ๋งŽ์ด ์‚ฌ์šฉ๋ผ! ๐Ÿ“ข

// ์˜ต์ €๋ฒ„ ์ธํ„ฐํŽ˜์ด์Šค
class Observer {
public:
    virtual ~Observer() {}
    virtual void update(const string& message) = 0;
};

// ์ฃผ์ฒด(Subject) ํด๋ž˜์Šค
class Subject {
private:
    vector<Observer*> observers;
    string state;
    
public:
    void attach(Observer* observer) {
        observers.push_back(observer);
    }
    
    void detach(Observer* observer) {
        observers.erase(
            remove(observers.begin(), observers.end(), observer),
            observers.end()
        );
    }
    
    void notify() {
        for (Observer* observer : observers) {
            observer->update(state);
        }
    }
    
    void setState(const string& newState) {
        state = newState;
        cout << "์ƒํƒœ ๋ณ€๊ฒฝ: " << state << endl;
        notify();  // ๋ชจ๋“  ์˜ต์ €๋ฒ„์—๊ฒŒ ์•Œ๋ฆผ!
    }
    
    string getState() const { return state; }
};

// ๊ตฌ์ฒด์ ์ธ ์˜ต์ €๋ฒ„๋“ค
class Player : public Observer {
private:
    string name;
    
public:
    Player(const string& n) : name(n) {}
    
    void update(const string& message) override {
        cout << "[ํ”Œ๋ ˆ์ด์–ด " << name << "] ์•Œ๋ฆผ ๋ฐ›์Œ: " 
             << message << " ๐ŸŽฎ" << endl;
    }
};

class UIDisplay : public Observer {
public:
    void update(const string& message) override {
        cout << "[UI ๋””์Šคํ”Œ๋ ˆ์ด] ํ™”๋ฉด ์—…๋ฐ์ดํŠธ: " 
             << message << " ๐Ÿ–ฅ๏ธ" << endl;
    }
};

class SoundSystem : public Observer {
public:
    void update(const string& message) override {
        cout << "[์‚ฌ์šด๋“œ ์‹œ์Šคํ…œ] ํšจ๊ณผ์Œ ์žฌ์ƒ: " 
             << message << " ๐Ÿ”Š" << endl;
    }
};

// ์‚ฌ์šฉ ์˜ˆ์‹œ
int main() {
    Subject gameState;
    
    Player player1("์ฒ ์ˆ˜");
    Player player2("์˜ํฌ");
    UIDisplay ui;
    SoundSystem sound;
    
    // ์˜ต์ €๋ฒ„ ๋“ฑ๋ก
    gameState.attach(&player1);
    gameState.attach(&player2);
    gameState.attach(&ui);
    gameState.attach(&sound);
    
    cout << "=== ๊ฒŒ์ž„ ์‹œ์ž‘ ===" << endl;
    gameState.setState("๊ฒŒ์ž„ ์‹œ์ž‘!");
    
    cout << "\n=== ์  ์ถœํ˜„ ===" << endl;
    gameState.setState("๋ณด์Šค ๋“ฑ์žฅ!");
    
    cout << "\n=== ํ”Œ๋ ˆ์ด์–ด2 ํ‡ด์žฅ ===" << endl;
    gameState.detach(&player2);
    gameState.setState("์•„์ดํ…œ ํš๋“!");
    
    return 0;
}
์˜ต์ €๋ฒ„ ํŒจํ„ด์€ GUI ํ”„๋กœ๊ทธ๋ž˜๋ฐ, ๊ฒŒ์ž„ ๊ฐœ๋ฐœ, ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์‹œ์Šคํ…œ์—์„œ ํ•„์ˆ˜์ ์ด์•ผ! ๐ŸŽฏ
๋””์ž์ธ ํŒจํ„ด ๋น„๊ต ํŒฉํ† ๋ฆฌ ํŒจํ„ด ๋ชฉ์  ๊ฐ์ฒด ์ƒ์„ฑ ๋กœ์ง ์บก์Аํ™” ์žฅ์  ์ƒ์„ฑ ๋กœ์ง ์ค‘์•™ํ™” ๊ฒฐํ•ฉ๋„ ๊ฐ์†Œ ํ™•์žฅ ์šฉ์ด ์‚ฌ์šฉ ์‹œ๊ธฐ ๋ณต์žกํ•œ ๊ฐ์ฒด ์ƒ์„ฑ ๋Ÿฐํƒ€์ž„ ํƒ€์ž… ๊ฒฐ์ • ๐Ÿญ ์ „๋žต ํŒจํ„ด ๋ชฉ์  ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ต์ฒด ๊ฐ€๋Šฅ ์žฅ์  ๋Ÿฐํƒ€์ž„ ๋™์ž‘ ๋ณ€๊ฒฝ ์กฐ๊ฑด๋ฌธ ์ œ๊ฑฐ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋…๋ฆฝ์„ฑ ์‚ฌ์šฉ ์‹œ๊ธฐ ์—ฌ๋Ÿฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์กด์žฌ ๋™์  ํ–‰๋™ ๋ณ€๊ฒฝ ํ•„์š” ๐ŸŽฏ ์˜ต์ €๋ฒ„ ํŒจํ„ด ๋ชฉ์  ์ƒํƒœ ๋ณ€๊ฒฝ ์ž๋™ ํ†ต์ง€ ์žฅ์  ๋А์Šจํ•œ ๊ฒฐํ•ฉ ๋™์  ๊ตฌ๋…/ํ•ด์ œ ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธ ํ†ต์‹  ์‚ฌ์šฉ ์‹œ๊ธฐ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ์‹œ์Šคํ…œ ์ƒํƒœ ๋™๊ธฐํ™” ํ•„์š” ๐Ÿ“ข

๐ŸŽญ ๋” ๋งŽ์€ ๋””์ž์ธ ํŒจํ„ด๋“ค

4๏ธโƒฃ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด (Singleton Pattern)

ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์˜ค์ง ํ•˜๋‚˜๋งŒ ์กด์žฌํ•˜๋„๋ก ๋ณด์žฅํ•˜๋Š” ํŒจํ„ด์ด์•ผ. ๊ฒŒ์ž„์˜ ๊ฒŒ์ž„ ๋งค๋‹ˆ์ €, ์„ค์ • ๊ด€๋ฆฌ์ž, ๋กœ๊ทธ ์‹œ์Šคํ…œ ๊ฐ™์€ ๊ณณ์—์„œ ๋งŽ์ด ์จ! ๐ŸŽฏ

class GameManager {
private:
    static GameManager* instance;
    int score;
    int level;
    
    // private ์ƒ์„ฑ์ž๋กœ ์™ธ๋ถ€ ์ƒ์„ฑ ์ฐจ๋‹จ!
    GameManager() : score(0), level(1) {
        cout << "๊ฒŒ์ž„ ๋งค๋‹ˆ์ € ์ดˆ๊ธฐํ™”" << endl;
    }
    
    // ๋ณต์‚ฌ ์ƒ์„ฑ์ž์™€ ๋Œ€์ž… ์—ฐ์‚ฐ์ž ์‚ญ์ œ
    GameManager(const GameManager&) = delete;
    GameManager& operator=(const GameManager&) = delete;
    
public:
    static GameManager* getInstance() {
        if (instance == nullptr) {
            instance = new GameManager();
        }
        return instance;
    }
    
    static void destroyInstance() {
        if (instance != nullptr) {
            delete instance;
            instance = nullptr;
        }
    }
    
    void addScore(int points) {
        score += points;
        cout << "์ ์ˆ˜ ํš๋“! ํ˜„์žฌ ์ ์ˆ˜: " << score << endl;
    }
    
    void levelUp() {
        level++;
        cout << "๋ ˆ๋ฒจ ์—…! ํ˜„์žฌ ๋ ˆ๋ฒจ: " << level << endl;
    }
    
    int getScore() const { return score; }
    int getLevel() const { return level; }
};

// static ๋ฉค๋ฒ„ ์ดˆ๊ธฐํ™”
GameManager* GameManager::instance = nullptr;

// ์‚ฌ์šฉ ์˜ˆ์‹œ
int main() {
    // ์–ด๋””์„œ๋“  ๊ฐ™์€ ์ธ์Šคํ„ด์Šค ์ ‘๊ทผ!
    GameManager* gm1 = GameManager::getInstance();
    gm1->addScore(100);
    
    GameManager* gm2 = GameManager::getInstance();
    gm2->levelUp();
    
    // gm1๊ณผ gm2๋Š” ๊ฐ™์€ ๊ฐ์ฒด!
    cout << "gm1 ์ ์ˆ˜: " << gm1->getScore() << endl;
    cout << "gm2 ์ ์ˆ˜: " << gm2->getScore() << endl;
    
    GameManager::destroyInstance();
    return 0;
}
โš ๏ธ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด ์ฃผ์˜์‚ฌํ•ญ!

์‹ฑ๊ธ€ํ†ค์€ ํŽธ๋ฆฌํ•˜์ง€๋งŒ ๋‚จ์šฉํ•˜๋ฉด ์•ˆ ๋ผ! ์ „์—ญ ์ƒํƒœ๋ฅผ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ์— ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ต๊ณ , ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์–ด. ์œ„ ์ฝ”๋“œ๋Š” ์Šค๋ ˆ๋“œ ์•ˆ์ „ํ•˜์ง€ ์•Š์œผ๋‹ˆ, ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” std::mutex๋‚˜ std::call_once๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ด! ๐Ÿ”’

5๏ธโƒฃ ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด (Template Method Pattern)

์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๊ณจ๊ฒฉ์„ ์ •์˜ํ•˜๊ณ , ์ผ๋ถ€ ๋‹จ๊ณ„๋ฅผ ์„œ๋ธŒํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„ํ•˜๊ฒŒ ํ•˜๋Š” ํŒจํ„ด์ด์•ผ. ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ์ด ์ •๋ง ์ข‹์•„์ ธ! ๐Ÿ“

class DataProcessor {
public:
    // ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ: ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๊ณจ๊ฒฉ
    void process() {
        loadData();
        validateData();
        processData();
        saveData();
        cleanup();
    }
    
    virtual ~DataProcessor() {}
    
protected:
    // ์„œ๋ธŒํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„ํ•  ์ˆœ์ˆ˜ ๊ฐ€์ƒํ•จ์ˆ˜๋“ค
    virtual void loadData() = 0;
    virtual void processData() = 0;
    virtual void saveData() = 0;
    
    // ๊ธฐ๋ณธ ๊ตฌํ˜„์„ ์ œ๊ณตํ•˜๋Š” ๊ฐ€์ƒํ•จ์ˆ˜
    virtual void validateData() {
        cout << "๋ฐ์ดํ„ฐ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ค‘..." << endl;
    }
    
    virtual void cleanup() {
        cout << "์ •๋ฆฌ ์ž‘์—… ์™„๋ฃŒ" << endl;
    }
};

class CSVProcessor : public DataProcessor {
protected:
    void loadData() override {
        cout << "CSV ํŒŒ์ผ ๋กœ๋”ฉ ์ค‘... ๐Ÿ“„" << endl;
    }
    
    void processData() override {
        cout << "CSV ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์ค‘... โš™๏ธ" << endl;
    }
    
    void saveData() override {
        cout << "CSV ํŒŒ์ผ๋กœ ์ €์žฅ ์ค‘... ๐Ÿ’พ" << endl;
    }
};

class JSONProcessor : public DataProcessor {
protected:
    void loadData() override {
        cout << "JSON ํŒŒ์ผ ๋กœ๋”ฉ ์ค‘... ๐Ÿ“‹" << endl;
    }
    
    void processData() override {
        cout << "JSON ๋ฐ์ดํ„ฐ ํŒŒ์‹ฑ ๋ฐ ์ฒ˜๋ฆฌ ์ค‘... โš™๏ธ" << endl;
    }
    
    void saveData() override {
        cout << "JSON ํŒŒ์ผ๋กœ ์ €์žฅ ์ค‘... ๐Ÿ’พ" << endl;
    }
    
    // ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œ
    void validateData() override {
        cout << "JSON ์Šคํ‚ค๋งˆ ๊ฒ€์ฆ ์ค‘... โœ…" << endl;
    }
};

// ์‚ฌ์šฉ ์˜ˆ์‹œ
int main() {
    cout << "=== CSV ์ฒ˜๋ฆฌ ===" << endl;
    DataProcessor* csv = new CSVProcessor();
    csv->process();
    
    cout << "\n=== JSON ์ฒ˜๋ฆฌ ===" << endl;
    DataProcessor* json = new JSONProcessor();
    json->process();
    
    delete csv;
    delete json;
    
    return 0;
}
ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด์€ ๊ณตํ†ต ๋กœ์ง์„ ๋ถ€๋ชจ ํด๋ž˜์Šค์— ๋‘๊ณ , ๋ณ€ํ•˜๋Š” ๋ถ€๋ถ„๋งŒ ์ž์‹ ํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„ํ•˜๊ฒŒ ํ•ด. ์ฝ”๋“œ ์ค‘๋ณต์„ ํ™• ์ค„์ผ ์ˆ˜ ์žˆ์–ด! ๐ŸŽจ

6๏ธโƒฃ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด (Decorator Pattern)

๊ฐ์ฒด์— ๋™์ ์œผ๋กœ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” ํŒจํ„ด์ด์•ผ. ์ƒ์† ๋Œ€์‹  ์กฐํ•ฉ์„ ์‚ฌ์šฉํ•ด์„œ ์œ ์—ฐ์„ฑ์ด ํ›จ์”ฌ ์ข‹์•„! ๐ŸŽ

// ๊ธฐ๋ณธ ์ปดํฌ๋„ŒํŠธ ์ธํ„ฐํŽ˜์ด์Šค
class Weapon {
public:
    virtual ~Weapon() {}
    virtual string getDescription() const = 0;
    virtual int getDamage() const = 0;
};

// ๊ธฐ๋ณธ ๋ฌด๊ธฐ
class BasicSword : public Weapon {
public:
    string getDescription() const override {
        return "๊ธฐ๋ณธ ๊ฒ€";
    }
    
    int getDamage() const override {
        return 10;
    }
};

// ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ธฐ๋ณธ ํด๋ž˜์Šค
class WeaponDecorator : public Weapon {
protected:
    Weapon* weapon;
    
public:
    WeaponDecorator(Weapon* w) : weapon(w) {}
    virtual ~WeaponDecorator() { delete weapon; }
};

// ๊ตฌ์ฒด์ ์ธ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋“ค
class FireEnchantment : public WeaponDecorator {
public:
    FireEnchantment(Weapon* w) : WeaponDecorator(w) {}
    
    string getDescription() const override {
        return weapon->getDescription() + " + ํ™”์—ผ ๊ฐ•ํ™” ๐Ÿ”ฅ";
    }
    
    int getDamage() const override {
        return weapon->getDamage() + 15;
    }
};

class PoisonEnchantment : public WeaponDecorator {
public:
    PoisonEnchantment(Weapon* w) : WeaponDecorator(w) {}
    
    string getDescription() const override {
        return weapon->getDescription() + " + ๋… ๊ฐ•ํ™” โ˜ ๏ธ";
    }
    
    int getDamage() const override {
        return weapon->getDamage() + 10;
    }
};

class SharpnessEnchantment : public WeaponDecorator {
public:
    SharpnessEnchantment(Weapon* w) : WeaponDecorator(w) {}
    
    string getDescription() const override {
        return weapon->getDescription() + " + ๋‚ ์นด๋กœ์›€ ๊ฐ•ํ™” โš”๏ธ";
    }
    
    int getDamage() const override {
        return weapon->getDamage() + 8;
    }
};

// ์‚ฌ์šฉ ์˜ˆ์‹œ
int main() {
    // ๊ธฐ๋ณธ ๊ฒ€
    Weapon* sword = new BasicSword();
    cout << sword->getDescription() << endl;
    cout << "๊ณต๊ฒฉ๋ ฅ: " << sword->getDamage() << endl << endl;
    
    // ํ™”์—ผ ๊ฐ•ํ™” ์ถ”๊ฐ€
    Weapon* fireSword = new FireEnchantment(new BasicSword());
    cout << fireSword->getDescription() << endl;
    cout << "๊ณต๊ฒฉ๋ ฅ: " << fireSword->getDamage() << endl << endl;
    
    // ์—ฌ๋Ÿฌ ๊ฐ•ํ™” ์ค‘์ฒฉ!
    Weapon* ultimateSword = new SharpnessEnchantment(
        new PoisonEnchantment(
            new FireEnchantment(
                new BasicSword()
            )
        )
    );
    cout << ultimateSword->getDescription() << endl;
    cout << "๊ณต๊ฒฉ๋ ฅ: " << ultimateSword->getDamage() << endl;
    
    delete sword;
    delete fireSword;
    delete ultimateSword;
    
    return 0;
}
๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด์€ ์ •๋ง ๊ฐ•๋ ฅํ•ด! ๋Ÿฐํƒ€์ž„์— ๊ธฐ๋Šฅ์„ ์ž์œ ๋กญ๊ฒŒ ์กฐํ•ฉํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ . ๊ฒŒ์ž„ ์•„์ดํ…œ ์‹œ์Šคํ…œ, UI ์ปดํฌ๋„ŒํŠธ ๊พธ๋ฏธ๊ธฐ ๋“ฑ์— ์™„๋ฒฝํ•ด! ๐ŸŽจ

๐Ÿงฉ SOLID ์›์น™๊ณผ ๊ฐ์ฒด์ง€ํ–ฅ ์„ค๊ณ„

๋””์ž์ธ ํŒจํ„ด์„ ์ œ๋Œ€๋กœ ํ™œ์šฉํ•˜๋ ค๋ฉด SOLID ์›์น™์„ ์ดํ•ดํ•ด์•ผ ํ•ด! ์ด๊ฑด ๊ฐ์ฒด์ง€ํ–ฅ ์„ค๊ณ„์˜ 5๋Œ€ ์›์น™์ด์•ผ. ๐Ÿ›๏ธ

์›์น™ ์„ค๋ช… ํ•ต์‹ฌ ๊ฐœ๋…
SRP
๋‹จ์ผ ์ฑ…์ž„
ํด๋ž˜์Šค๋Š” ํ•˜๋‚˜์˜ ์ฑ…์ž„๋งŒ ๊ฐ€์ ธ์•ผ ํ•ด ํ•œ ํด๋ž˜์Šค๋Š” ํ•œ ๊ฐ€์ง€ ์ด์œ ๋กœ๋งŒ ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•จ
OCP
๊ฐœ๋ฐฉ-ํ์‡„
ํ™•์žฅ์—๋Š” ์—ด๋ ค์žˆ๊ณ  ์ˆ˜์ •์—๋Š” ๋‹ซํ˜€์žˆ์–ด์•ผ ํ•ด ์ƒˆ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ์‹œ ๊ธฐ์กด ์ฝ”๋“œ ์ˆ˜์ • ์ตœ์†Œํ™”
LSP
๋ฆฌ์Šค์ฝ”ํ”„ ์น˜ํ™˜
์ž์‹ ํด๋ž˜์Šค๋Š” ๋ถ€๋ชจ ํด๋ž˜์Šค๋ฅผ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ด ๋‹คํ˜•์„ฑ์˜ ๊ธฐ๋ณธ ์›์น™
ISP
์ธํ„ฐํŽ˜์ด์Šค ๋ถ„๋ฆฌ
ํด๋ผ์ด์–ธํŠธ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กดํ•˜๋ฉด ์•ˆ ๋ผ ์ž‘๊ณ  ๊ตฌ์ฒด์ ์ธ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์ข‹์•„
DIP
์˜์กด์„ฑ ์—ญ์ „
๊ตฌ์ฒด์ ์ธ ๊ฒƒ์ด ์•„๋‹Œ ์ถ”์ƒ์ ์ธ ๊ฒƒ์— ์˜์กดํ•ด์•ผ ํ•ด ๊ณ ์ˆ˜์ค€ ๋ชจ๋“ˆ์ด ์ €์ˆ˜์ค€ ๋ชจ๋“ˆ์— ์˜์กดํ•˜๋ฉด ์•ˆ ๋จ

๐ŸŽฏ SOLID ์›์น™ ์‹ค์ „ ์˜ˆ์ œ

1๏ธโƒฃ ๋‹จ์ผ ์ฑ…์ž„ ์›์น™ (SRP) ์œ„๋ฐ˜ ์˜ˆ์‹œ์™€ ๊ฐœ์„ 

// โŒ ๋‚˜์œ ์˜ˆ: ์—ฌ๋Ÿฌ ์ฑ…์ž„์„ ๊ฐ€์ง„ ํด๋ž˜์Šค
class User {
private:
    string name;
    string email;
    
public:
    void setName(const string& n) { name = n; }
    void setEmail(const string& e) { email = e; }
    
    // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ €์žฅ (์ฑ…์ž„ 1)
    void saveToDatabase() {
        cout << "DB์— ์ €์žฅ..." << endl;
    }
    
    // ์ด๋ฉ”์ผ ์ „์†ก (์ฑ…์ž„ 2)
    void sendEmail(const string& message) {
        cout << "์ด๋ฉ”์ผ ์ „์†ก..." << endl;
    }
    
    // ๋กœ๊ทธ ๊ธฐ๋ก (์ฑ…์ž„ 3)
    void log(const string& action) {
        cout << "๋กœ๊ทธ: " << action << endl;
    }
};

// โœ… ์ข‹์€ ์˜ˆ: ์ฑ…์ž„์„ ๋ถ„๋ฆฌ
class User {
private:
    string name;
    string email;
    
public:
    void setName(const string& n) { name = n; }
    void setEmail(const string& e) { email = e; }
    string getName() const { return name; }
    string getEmail() const { return email; }
};

class UserRepository {
public:
    void save(const User& user) {
        cout << "DB์— " << user.getName() << " ์ €์žฅ" << endl;
    }
};

class EmailService {
public:
    void send(const User& user, const string& message) {
        cout << user.getEmail() << "๋กœ ์ด๋ฉ”์ผ ์ „์†ก" << endl;
    }
};

class Logger {
public:
    void log(const string& action) {
        cout << "๋กœ๊ทธ: " << action << endl;
    }
};
์ด๋ ‡๊ฒŒ ์ฑ…์ž„์„ ๋ถ„๋ฆฌํ•˜๋ฉด ๊ฐ ํด๋ž˜์Šค๊ฐ€ ํ•˜๋‚˜์˜ ์ด์œ ๋กœ๋งŒ ๋ณ€๊ฒฝ๋ผ. ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ํ›จ์”ฌ ์‰ฌ์›Œ์ง€์ง€! ๐ŸŽฏ

2๏ธโƒฃ ๊ฐœ๋ฐฉ-ํ์‡„ ์›์น™ (OCP) ์ ์šฉ

// โœ… OCP๋ฅผ ๋”ฐ๋ฅด๋Š” ์„ค๊ณ„
class Shape {
public:
    virtual ~Shape() {}
    virtual double calculateArea() const = 0;
};

class Circle : public Shape {
private:
    double radius;
public:
    Circle(double r) : radius(r) {}
    double calculateArea() const override {
        return 3.14159 * radius * radius;
    }
};

class Rectangle : public Shape {
private:
    double width, height;
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    double calculateArea() const override {
        return width * height;
    }
};

// ์ƒˆ๋กœ์šด ๋„ํ˜• ์ถ”๊ฐ€ ์‹œ ๊ธฐ์กด ์ฝ”๋“œ ์ˆ˜์ • ๋ถˆํ•„์š”!
class Triangle : public Shape {
private:
    double base, height;
public:
    Triangle(double b, double h) : base(b), height(h) {}
    double calculateArea() const override {
        return 0.5 * base * height;
    }
};

class AreaCalculator {
public:
    double calculateTotalArea(const vector<Shape*>& shapes) {
        double total = 0;
        for (const Shape* shape : shapes) {
            total += shape->calculateArea();
        }
        return total;
    }
};
์ƒˆ๋กœ์šด ๋„ํ˜•์„ ์ถ”๊ฐ€ํ•ด๋„ AreaCalculator ํด๋ž˜์Šค๋Š” ์ „ํ˜€ ์ˆ˜์ •ํ•  ํ•„์š”๊ฐ€ ์—†์–ด! ์ด๊ฒŒ ๋ฐ”๋กœ OCP์˜ ํž˜์ด์•ผ! ๐Ÿ’ช

3๏ธโƒฃ ์˜์กด์„ฑ ์—ญ์ „ ์›์น™ (DIP) ์ ์šฉ

// โŒ ๋‚˜์œ ์˜ˆ: ๊ตฌ์ฒด ํด๋ž˜์Šค์— ์˜์กด
class MySQLDatabase {
public:
    void connect() { cout << "MySQL ์—ฐ๊ฒฐ" << endl; }
    void query(const string& sql) { cout << "์ฟผ๋ฆฌ ์‹คํ–‰: " << sql << endl; }
};

class UserService {
private:
    MySQLDatabase db;  // ๊ตฌ์ฒด ํด๋ž˜์Šค์— ์ง์ ‘ ์˜์กด!
public:
    void getUser(int id) {
        db.connect();
        db.query("SELECT * FROM users WHERE id = " + to_string(id));
    }
};

// โœ… ์ข‹์€ ์˜ˆ: ์ถ”์ƒํ™”์— ์˜์กด
class IDatabase {
public:
    virtual ~IDatabase() {}
    virtual void connect() = 0;
    virtual void query(const string& sql) = 0;
};

class MySQLDatabase : public IDatabase {
public:
    void connect() override { cout << "MySQL ์—ฐ๊ฒฐ" << endl; }
    void query(const string& sql) override { 
        cout << "MySQL ์ฟผ๋ฆฌ: " << sql << endl; 
    }
};

class PostgreSQLDatabase : public IDatabase {
public:
    void connect() override { cout << "PostgreSQL ์—ฐ๊ฒฐ" << endl; }
    void query(const string& sql) override { 
        cout << "PostgreSQL ์ฟผ๋ฆฌ: " << sql << endl; 
    }
};

class UserService {
private:
    IDatabase* db;  // ์ถ”์ƒํ™”์— ์˜์กด!
public:
    UserService(IDatabase* database) : db(database) {}
    
    void getUser(int id) {
        db->connect();
        db->query("SELECT * FROM users WHERE id = " + to_string(id));
    }
};

// ์‚ฌ์šฉ ์˜ˆ์‹œ
int main() {
    // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‰ฝ๊ฒŒ ๊ต์ฒด ๊ฐ€๋Šฅ!
    IDatabase* mysql = new MySQLDatabase();
    UserService service1(mysql);
    service1.getUser(1);
    
    IDatabase* postgres = new PostgreSQLDatabase();
    UserService service2(postgres);
    service2.getUser(2);
    
    delete mysql;
    delete postgres;
    return 0;
}
DIP๋ฅผ ์ ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ MySQL์—์„œ PostgreSQL๋กœ ๋ฐ”๊ฟ”๋„ UserService ์ฝ”๋“œ๋Š” ์ „ํ˜€ ์ˆ˜์ •ํ•  ํ•„์š”๊ฐ€ ์—†์–ด! ๐ŸŽ‰
SOLID ์›์น™ ํ•œ๋ˆˆ์— ๋ณด๊ธฐ S ๋‹จ์ผ ์ฑ…์ž„ ํ•˜๋‚˜์˜ ํด๋ž˜์Šค๋Š” ํ•˜๋‚˜์˜ ์ฑ…์ž„๋งŒ O ๊ฐœ๋ฐฉ-ํ์‡„ ํ™•์žฅ์— ์—ด๋ ค์žˆ๊ณ  ์ˆ˜์ •์— ๋‹ซํ˜€์žˆ๊ฒŒ L ๋ฆฌ์Šค์ฝ”ํ”„ ์น˜ํ™˜ ์ž์‹์€ ๋ถ€๋ชจ๋ฅผ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ์–ด์•ผ I ์ธํ„ฐํŽ˜์ด์Šค ๋ถ„๋ฆฌ ํ•„์š”ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์˜์กดํ•˜๋„๋ก D ์˜์กด์„ฑ ์—ญ์ „ ์ถ”์ƒํ™”์— ์˜์กดํ•˜๊ณ  ๊ตฌ์ฒดํ™”์— ์˜์กด ๊ธˆ์ง€

๐Ÿš€ ์‹ค๋ฌด ํ”„๋กœ์ ํŠธ ์˜ˆ์ œ: ๊ฒŒ์ž„ ์—”์ง„ ์„ค๊ณ„

์ž, ์ด์ œ ๋ฐฐ์šด ๊ฑธ ์ „๋ถ€ ํ™œ์šฉํ•ด์„œ ๊ฐ„๋‹จํ•œ ๊ฒŒ์ž„ ์—”์ง„์„ ์„ค๊ณ„ํ•ด๋ณด์ž! ์ด๊ฑด ์‹ค์ œ ์žฌ๋Šฅ๋„ท์—์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•  ๋•Œ๋„ ์ •๋ง ์œ ์šฉํ•œ ์˜ˆ์ œ์•ผ. ๐ŸŽฎ

// ========== ์ปดํฌ๋„ŒํŠธ ์‹œ์Šคํ…œ ==========
class Component {
public:
    virtual ~Component() {}
    virtual void update(float deltaTime) = 0;
    virtual string getType() const = 0;
};

class TransformComponent : public Component {
private:
    float x, y;
    float rotation;
    
public:
    TransformComponent(float px = 0, float py = 0) 
        : x(px), y(py), rotation(0) {}
    
    void update(float deltaTime) override {
        // ์œ„์น˜ ์—…๋ฐ์ดํŠธ ๋กœ์ง
    }
    
    string getType() const override { return "Transform"; }
    
    void setPosition(float px, float py) { x = px; y = py; }
    void move(float dx, float dy) { x += dx; y += dy; }
    float getX() const { return x; }
    float getY() const { return y; }
};

class RenderComponent : public Component {
private:
    string spriteName;
    
public:
    RenderComponent(const string& sprite) : spriteName(sprite) {}
    
    void update(float deltaTime) override {
        // ๋ Œ๋”๋ง ๋กœ์ง
        cout << "๋ Œ๋”๋ง: " << spriteName << endl;
    }
    
    string getType() const override { return "Render"; }
};

class PhysicsComponent : public Component {
private:
    float velocityX, velocityY;
    float mass;
    
public:
    PhysicsComponent(float m = 1.0f) 
        : velocityX(0), velocityY(0), mass(m) {}
    
    void update(float deltaTime) override {
        // ๋ฌผ๋ฆฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜
    }
    
    string getType() const override { return "Physics"; }
    
    void applyForce(float fx, float fy) {
        velocityX += fx / mass;
        velocityY += fy / mass;
    }
};

// ========== ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ ==========
class GameObject {
private:
    string name;
    vector<Component*> components;
    bool active;
    
public:
    GameObject(const string& n) : name(n), active(true) {}
    
    ~GameObject() {
        for (Component* comp : components) {
            delete comp;
        }
    }
    
    void addComponent(Component* component) {
        components.push_back(component);
    }
    
    template<typename T>
    T* getComponent() {
        for (Component* comp : components) {
            T* result = dynamic_cast<T*>(comp);
            if (result != nullptr) {
                return result;
            }
        }
        return nullptr;
    }
    
    void update(float deltaTime) {
        if (!active) return;
        
        for (Component* comp : components) {
            comp->update(deltaTime);
        }
    }
    
    void setActive(bool isActive) { active = isActive; }
    bool isActive() const { return active; }
    string getName() const { return name; }
};

// ========== ์”ฌ ๊ด€๋ฆฌ ==========
class Scene {
private:
    string name;
    vector<GameObject*> gameObjects;
    
public:
    Scene(const string& n) : name(n) {}
    
    ~Scene() {
        for (GameObject* obj : gameObjects) {
            delete obj;
        }
    }
    
    void addGameObject(GameObject* obj) {
        gameObjects.push_back(obj);
    }
    
    void update(float deltaTime) {
        for (GameObject* obj : gameObjects) {
            if (obj->isActive()) {
                obj->update(deltaTime);
            }
        }
    }
    
    GameObject* findGameObject(const string& name) {
        for (GameObject* obj : gameObjects) {
            if (obj->getName() == name) {
                return obj;
            }
        }
        return nullptr;
    }
    
    string getName() const { return name; }
};

// ========== ๊ฒŒ์ž„ ์—”์ง„ (์‹ฑ๊ธ€ํ†ค) ==========
class GameEngine {
private:
    static GameEngine* instance;
    Scene* currentScene;
    bool running;
    
    GameEngine() : currentScene(nullptr), running(false) {}
    
public:
    static GameEngine* getInstance() {
        if (instance == nullptr) {
            instance = new GameEngine();
        }
        return instance;
    }
    
    void loadScene(Scene* scene) {
        if (currentScene != nullptr) {
            delete currentScene;
        }
        currentScene = scene;
        cout << "์”ฌ ๋กœ๋“œ: " << scene->getName() << " ๐ŸŽฌ" << endl;
    }
    
    void start() {
        running = true;
        cout << "๊ฒŒ์ž„ ์‹œ์ž‘! ๐ŸŽฎ" << endl;
    }
    
    void update(float deltaTime) {
        if (running && currentScene != nullptr) {
            currentScene->update(deltaTime);
        }
    }
    
    void stop() {
        running = false;
        cout << "๊ฒŒ์ž„ ์ข…๋ฃŒ! ๐Ÿ‘‹" << endl;
    }
    
    Scene* getCurrentScene() { return currentScene; }
};

GameEngine* GameEngine::instance = nullptr;

// ========== ์‚ฌ์šฉ ์˜ˆ์‹œ ==========
int main() {
    GameEngine* engine = GameEngine::getInstance();
    
    // ์”ฌ ์ƒ์„ฑ
    Scene* mainScene = new Scene("๋ฉ”์ธ ๊ฒŒ์ž„");
    
    // ํ”Œ๋ ˆ์ด์–ด ์˜ค๋ธŒ์ ํŠธ ์ƒ์„ฑ
    GameObject* player = new GameObject("ํ”Œ๋ ˆ์ด์–ด");
    player->addComponent(new TransformComponent(100, 100));
    player->addComponent(new RenderComponent("player_sprite.png"));
    player->addComponent(new PhysicsComponent(1.5f));
    mainScene->addGameObject(player);
    
    // ์  ์˜ค๋ธŒ์ ํŠธ ์ƒ์„ฑ
    GameObject* enemy = new GameObject("์ ");
    enemy->addComponent(new TransformComponent(300, 200));
    enemy->addComponent(new RenderComponent("enemy_sprite.png"));
    enemy->addComponent(new PhysicsComponent(1.0f));
    mainScene->addGameObject(enemy);
    
    // ๋ฐฐ๊ฒฝ ์˜ค๋ธŒ์ ํŠธ
    GameObject* background = new GameObject("๋ฐฐ๊ฒฝ");
    background->addComponent(new TransformComponent(0, 0));
    background->addComponent(new RenderComponent("background.png"));
    mainScene->addGameObject(background);
    
    // ๊ฒŒ์ž„ ์‹คํ–‰
    engine->loadScene(mainScene);
    engine->start();
    
    // ๊ฒŒ์ž„ ๋ฃจํ”„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜
    cout << "\n=== ๊ฒŒ์ž„ ๋ฃจํ”„ ์‹œ์ž‘ ===" << endl;
    for (int i = 0; i < 3; i++) {
        cout << "\n--- ํ”„๋ ˆ์ž„ " << i + 1 << " ---" << endl;
        engine->update(0.016f);  // ์•ฝ 60 FPS
        
        // ํ”Œ๋ ˆ์ด์–ด ์ด๋™
        TransformComponent* playerTransform = 
            player->getComponent<TransformComponent>();
        if (playerTransform) {
            playerTransform->move(10, 0);
            cout << "ํ”Œ๋ ˆ์ด์–ด ์œ„์น˜: (" 
                 << playerTransform->getX() << ", " 
                 << playerTransform->getY() << ")" << endl;
        }
    }
    
    engine->stop();
    
    return 0;
}
๐ŸŽฏ ์ด ๊ฒŒ์ž„ ์—”์ง„ ์„ค๊ณ„์˜ ํ•ต์‹ฌ ํฌ์ธํŠธ!

โœ… ์ปดํฌ๋„ŒํŠธ ํŒจํ„ด: ๊ธฐ๋Šฅ์„ ๋…๋ฆฝ์ ์ธ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ถ„๋ฆฌ
โœ… ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด: ๊ฒŒ์ž„ ์—”์ง„์€ ํ•˜๋‚˜๋งŒ ์กด์žฌ
โœ… ๋‹คํ˜•์„ฑ ํ™œ์šฉ: Component ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋‹ค์–‘ํ•œ ์ปดํฌ๋„ŒํŠธ ๊ด€๋ฆฌ
โœ… SOLID ์›์น™ ์ค€์ˆ˜: ๊ฐ ํด๋ž˜์Šค๊ฐ€ ๋ช…ํ™•ํ•œ ์ฑ…์ž„์„ ๊ฐ€์ง
โœ… ํ™•์žฅ์„ฑ: ์ƒˆ๋กœ์šด ์ปดํฌ๋„ŒํŠธ ํƒ€์ž…์„ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ!

์ด๋Ÿฐ ๊ตฌ์กฐ๋Š” Unity๋‚˜ Unreal Engine ๊ฐ™์€ ์‹ค์ œ ๊ฒŒ์ž„ ์—”์ง„์—์„œ๋„ ์‚ฌ์šฉํ•˜๋Š” ํŒจํ„ด์ด์•ผ! ๐ŸŽฎ

๐Ÿ’ก ์‹ค๋ฌด ํŒ๊ณผ ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค

์ด์ œ ์‹ค๋ฌด์—์„œ ์ •๋ง ์ค‘์š”ํ•œ ํŒ๋“ค์„ ์•Œ๋ ค์ค„๊ฒŒ! ์ด๊ฑด ๋‚ด๊ฐ€ ์ง์ ‘ ๊ฒฝํ—˜ํ•˜๋ฉด์„œ ๋ฐฐ์šด ๊ฒƒ๋“ค์ด์•ผ. ๐Ÿ˜Š

1๏ธโƒฃ ๊ฐ€์ƒํ•จ์ˆ˜ ์„ฑ๋Šฅ ๊ณ ๋ ค์‚ฌํ•ญ

๊ฐ€์ƒํ•จ์ˆ˜๋Š” ํŽธ๋ฆฌํ•˜์ง€๋งŒ ์•ฝ๊ฐ„์˜ ์„ฑ๋Šฅ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์žˆ์–ด. vtable์„ ํ†ตํ•œ ๊ฐ„์ ‘ ํ˜ธ์ถœ์ด ์ผ๋ฐ˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋ณด๋‹ค ๋А๋ฆฌ๊ฑฐ๋“ . ํ•˜์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ์ด ์ฐจ์ด๋Š” ๋ฌด์‹œํ•  ์ˆ˜ ์žˆ๋Š” ์ˆ˜์ค€์ด์•ผ! ๐Ÿš€

// ์„ฑ๋Šฅ์ด ์ •๋ง ์ค‘์š”ํ•œ ๊ฒฝ์šฐ
class FastObject {
public:
    // final์„ ๋ถ™์ด๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ตœ์ ํ™” ๊ฐ€๋Šฅ!
    virtual void criticalFunction() final {
        // ์„ฑ๋Šฅ ์ค‘์š”ํ•œ ์ฝ”๋“œ
    }
};

// ๋˜๋Š” ํ…œํ”Œ๋ฆฟ์œผ๋กœ ์ปดํŒŒ์ผ ํƒ€์ž„ ๋‹คํ˜•์„ฑ ํ™œ์šฉ
template<typename T>
class OptimizedContainer {
public:
    void process(T& item) {
        item.doSomething();  // ๊ฐ€์ƒํ•จ์ˆ˜ ํ˜ธ์ถœ ์—†์Œ!
    }
};

2๏ธโƒฃ ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ ํ™œ์šฉํ•˜๊ธฐ

๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋Š” C++์—์„œ ์ •๋ง ์ค‘์š”ํ•ด! ์š”์ฆ˜์€ new/delete ๋Œ€์‹  ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ํ‘œ์ค€์ด์•ผ. ๐ŸŽฏ

#include <memory>

class ModernGameObject {
private:
    vector<unique_ptr<Component>> components;  // ์ž๋™ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ!
    
public:
    void addComponent(unique_ptr<Component> comp) {
        components.push_back(move(comp));
    }
    
    // ์†Œ๋ฉธ์ž์—์„œ delete ํ•  ํ•„์š” ์—†์Œ!
    ~ModernGameObject() = default;
};

// ์‚ฌ์šฉ ์˜ˆ์‹œ
int main() {
    auto obj = make_unique<ModernGameObject>();
    obj->addComponent(make_unique<TransformComponent>(0, 0));
    obj->addComponent(make_unique<RenderComponent>("sprite.png"));
    
    // obj๊ฐ€ ์Šค์ฝ”ํ”„๋ฅผ ๋ฒ—์–ด๋‚˜๋ฉด ์ž๋™์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ!
    return 0;
}
๐Ÿ“š ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ ์„ ํƒ ๊ฐ€์ด๋“œ

๐Ÿ”น unique_ptr: ๋‹จ๋… ์†Œ์œ ๊ถŒ, ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ
๐Ÿ”น shared_ptr: ๊ณต์œ  ์†Œ์œ ๊ถŒ, ์ฐธ์กฐ ์นด์šดํŒ…
๐Ÿ”น weak_ptr: ์ˆœํ™˜ ์ฐธ์กฐ ๋ฐฉ์ง€์šฉ

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ unique_ptr๋กœ ์ถฉ๋ถ„ํ•ด! ํ•„์š”ํ•  ๋•Œ๋งŒ shared_ptr์„ ์‚ฌ์šฉํ•˜์ž. ๐ŸŽฏ

3๏ธโƒฃ ์ธํ„ฐํŽ˜์ด์Šค ์„ค๊ณ„ ์›์น™

์ข‹์€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์„ค๊ณ„ํ•˜๋Š” ๊ฑด ์ •๋ง ์ค‘์š”ํ•ด! ๋ช‡ ๊ฐ€์ง€ ์›์น™์„ ์•Œ๋ ค์ค„๊ฒŒ. ๐Ÿ“

โœ… DO: ์ž‘๊ณ  ์ง‘์ค‘๋œ ์ธํ„ฐํŽ˜์ด์Šค

// ์ข‹์€ ์˜ˆ: ๊ฐ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋ช…ํ™•ํ•œ ์—ญํ• 
class IMovable {
public:
    virtual void move(float dx, float dy) = 0;
    virtual ~IMovable() {}
};

class IRenderable {
public:
    virtual void render() = 0;
    virtual ~IRenderable() {}
};

class ICollidable {
public:
    virtual bool checkCollision(const ICollidable& other) = 0;
    virtual ~ICollidable() {}
};
โŒ DON'T: ๊ฑฐ๋Œ€ํ•œ ์ธํ„ฐํŽ˜์ด์Šค

// ๋‚˜์œ ์˜ˆ: ๋„ˆ๋ฌด ๋งŽ์€ ์ฑ…์ž„
class IGameObject {
public:
    virtual void move(float dx, float dy) = 0;
    virtual void render() = 0;
    virtual bool checkCollision(const IGameObject& other) = 0;
    virtual void playSound() = 0;
    virtual void updateAI() = 0;
    virtual void saveToFile() = 0;
    // ... ๋„ˆ๋ฌด ๋งŽ์•„!
};

4๏ธโƒฃ ์˜ˆ์™ธ ์•ˆ์ „์„ฑ ๋ณด์žฅ

๊ฐ€์ƒํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋„ ์‹ ๊ฒฝ ์จ์•ผ ํ•ด! ๐Ÿ›ก๏ธ

class SafeComponent : public Component {
public:
    void update(float deltaTime) override {
        try {
            // ์œ„ํ—˜ํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์—…
            performUpdate(deltaTime);
        } catch (const exception& e) {
            // ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
            cerr << "์ปดํฌ๋„ŒํŠธ ์—…๋ฐ์ดํŠธ ์‹คํŒจ: " << e.what() << endl;
            // ๋ณต๊ตฌ ๋กœ์ง
        }
    }
    
private:
    void performUpdate(float deltaTime) {
        // ์‹ค์ œ ์—…๋ฐ์ดํŠธ ๋กœ์ง
    }
};

5๏ธโƒฃ ๋ฌธ์„œํ™”์™€ ์ฃผ์„

์ธํ„ฐํŽ˜์ด์Šค๋Š” ํŠนํžˆ ์ž˜ ๋ฌธ์„œํ™”ํ•ด์•ผ ํ•ด! ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค์ด ์‚ฌ์šฉํ•  ๊ฑฐ๋‹ˆ๊นŒ. ๐Ÿ“š

/**
 * @brief ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์˜ ๊ธฐ๋ณธ ์ปดํฌ๋„ŒํŠธ ์ธํ„ฐํŽ˜์ด์Šค
 * 
 * ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋Š” ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
 * ๊ฐ ํ”„๋ ˆ์ž„๋งˆ๋‹ค update() ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
 */
class Component {
public:
    virtual ~Component() {}
    
    /**
     * @brief ์ปดํฌ๋„ŒํŠธ ์—…๋ฐ์ดํŠธ
     * @param deltaTime ์ด์ „ ํ”„๋ ˆ์ž„์œผ๋กœ๋ถ€ํ„ฐ ๊ฒฝ๊ณผํ•œ ์‹œ๊ฐ„ (์ดˆ ๋‹จ์œ„)
     * 
     * ์ด ๋ฉ”์„œ๋“œ๋Š” ๋งค ํ”„๋ ˆ์ž„๋งˆ๋‹ค ํ˜ธ์ถœ๋˜๋ฏ€๋กœ ์„ฑ๋Šฅ์— ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
     */
    virtual void update(float deltaTime) = 0;
    
    /**
     * @brief ์ปดํฌ๋„ŒํŠธ ํƒ€์ž… ๋ฐ˜ํ™˜
     * @return ์ปดํฌ๋„ŒํŠธ์˜ ํƒ€์ž… ๋ฌธ์ž์—ด
     */
    virtual string getType() const = 0;
};

๐ŸŽ“ ํ•™์Šต ๋กœ๋“œ๋งต๊ณผ ์ถ”์ฒœ ์ž๋ฃŒ

C++ ๊ฐ์ฒด์ง€ํ–ฅ๊ณผ ๋””์ž์ธ ํŒจํ„ด์„ ๋งˆ์Šคํ„ฐํ•˜๋Š” ๊ฑด ์‹œ๊ฐ„์ด ๊ฑธ๋ ค. ํ•˜์ง€๋งŒ ์ฒด๊ณ„์ ์œผ๋กœ ๊ณต๋ถ€ํ•˜๋ฉด ์ถฉ๋ถ„ํžˆ ํ•  ์ˆ˜ ์žˆ์–ด! ์—ฌ๊ธฐ ๋‚ด๊ฐ€ ์ถ”์ฒœํ•˜๋Š” ํ•™์Šต ๋กœ๋“œ๋งต์ด์•ผ. ๐Ÿ—บ๏ธ

๐Ÿ“š ๋‹จ๊ณ„๋ณ„ ํ•™์Šต ๋กœ๋“œ๋งต

1๋‹จ๊ณ„: ๊ธฐ์ดˆ ๋‹ค์ง€๊ธฐ (1-2๊ฐœ์›”)
โœ… C++ ๊ธฐ๋ณธ ๋ฌธ๋ฒ• ์™„๋ฒฝ ์ดํ•ด
โœ… ํด๋ž˜์Šค์™€ ๊ฐ์ฒด ๊ฐœ๋…
โœ… ์ƒ์†๊ณผ ๋‹คํ˜•์„ฑ ๊ธฐ์ดˆ
โœ… ํฌ์ธํ„ฐ์™€ ์ฐธ์กฐ ๋งˆ์Šคํ„ฐ

2๋‹จ๊ณ„: ๊ฐ์ฒด์ง€ํ–ฅ ์‹ฌํ™” (2-3๊ฐœ์›”)
โœ… ๊ฐ€์ƒํ•จ์ˆ˜์™€ ์ˆœ์ˆ˜ ๊ฐ€์ƒํ•จ์ˆ˜
โœ… ์ถ”์ƒํด๋ž˜์Šค์™€ ์ธํ„ฐํŽ˜์ด์Šค
โœ… ์—ฐ์‚ฐ์ž ์˜ค๋ฒ„๋กœ๋”ฉ
โœ… ํ…œํ”Œ๋ฆฟ ํ”„๋กœ๊ทธ๋ž˜๋ฐ

3๋‹จ๊ณ„: ๋””์ž์ธ ํŒจํ„ด (2-3๊ฐœ์›”)
โœ… GoF ๋””์ž์ธ ํŒจํ„ด 23๊ฐ€์ง€ ํ•™์Šต
โœ… ์‹ค์ „ ํ”„๋กœ์ ํŠธ์— ์ ์šฉ
โœ… ๋ฆฌํŒฉํ† ๋ง ์—ฐ์Šต
โœ… ์ฝ”๋“œ ๋ฆฌ๋ทฐ ์ฐธ์—ฌ

4๋‹จ๊ณ„: ์‹ค๋ฌด ํ”„๋กœ์ ํŠธ (๊ณ„์†)
โœ… ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ ๊ธฐ์—ฌ
โœ… ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ ์ง„ํ–‰
โœ… ์ฝ”๋“œ ํ’ˆ์งˆ ๊ฐœ์„ 
โœ… ์„ฑ๋Šฅ ์ตœ์ ํ™”

๐ŸŽฏ ์‹ค์ „ ์—ฐ์Šต ํ”„๋กœ์ ํŠธ ์•„์ด๋””์–ด

1๏ธโƒฃ ๊ฐ„๋‹จํ•œ ๊ฒŒ์ž„ ์—”์ง„: 2D ๊ฒŒ์ž„ ์—”์ง„์„ ๋งŒ๋“ค์–ด๋ณด์ž
2๏ธโƒฃ ๊ทธ๋ž˜ํ”ฝ ์—๋””ํ„ฐ: ๋„ํ˜• ๊ทธ๋ฆฌ๊ธฐ ํ”„๋กœ๊ทธ๋žจ
3๏ธโƒฃ ์ฑ„ํŒ… ์„œ๋ฒ„: ๋„คํŠธ์›Œํฌ ํ”„๋กœ๊ทธ๋ž˜๋ฐ + ๋””์ž์ธ ํŒจํ„ด
4๏ธโƒฃ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ORM: ๊ฐ์ฒด-๊ด€๊ณ„ ๋งคํ•‘ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
5๏ธโƒฃ ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹œ์Šคํ…œ: ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜

์ด๋Ÿฐ ํ”„๋กœ์ ํŠธ๋“ค์„ ์žฌ๋Šฅ๋„ท์—์„œ ํฌํŠธํด๋ฆฌ์˜ค๋กœ ๊ณต์œ ํ•˜๋ฉด ์ •๋ง ์ข‹์•„! ๐ŸŒŸ

๐Ÿ’ป ์ถ”์ฒœ ํ•™์Šต ์ž๋ฃŒ

๐Ÿ“– ํ•„๋… ์„œ์ 
โ€ข "Effective C++" - Scott Meyers
โ€ข "Design Patterns" - GoF
โ€ข "Clean Code" - Robert C. Martin
โ€ข "C++ Primer" - Stanley Lippman

๐ŸŒ ์˜จ๋ผ์ธ ๋ฆฌ์†Œ์Šค
โ€ข cppreference.com - C++ ๋ ˆํผ๋Ÿฐ์Šค
โ€ข learncpp.com - ์ฒด๊ณ„์ ์ธ C++ ํŠœํ† ๋ฆฌ์–ผ
โ€ข GitHub - ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ ๋ถ„์„
โ€ข Stack Overflow - ๋ฌธ์ œ ํ•ด๊ฒฐ

๐ŸŽฎ ์‹ค์Šต ํ”Œ๋žซํผ
โ€ข LeetCode - ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ฌธ์ œ
โ€ข HackerRank - C++ ์ฑŒ๋ฆฐ์ง€
โ€ข Codewars - ์ฝ”๋”ฉ ์—ฐ์Šต
โ€ข ์žฌ๋Šฅ๋„ท - ํ”„๋กœ์ ํŠธ ๊ณต์œ  ๋ฐ ํ”ผ๋“œ๋ฐฑ!

๐Ÿ”ฅ ํ”ํ•œ ์‹ค์ˆ˜์™€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

๋งˆ์ง€๋ง‰์œผ๋กœ ์ดˆ๋ณด์ž๋“ค์ด ์ž์ฃผ ํ•˜๋Š” ์‹ค์ˆ˜๋“ค๊ณผ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์•Œ๋ ค์ค„๊ฒŒ! ๋‚˜๋„ ๋‹ค ๊ฒช์–ด๋ณธ ์‹ค์ˆ˜๋“ค์ด์•ผ. ๐Ÿ˜…

โŒ ์‹ค์ˆ˜ 1: ๊ฐ€์ƒ ์†Œ๋ฉธ์ž ๋นผ๋จน๊ธฐ

// ๋ฌธ์ œ ์ฝ”๋“œ
class Base {
public:
    ~Base() { cout << "Base ์†Œ๋ฉธ" << endl; }  // virtual ์—†์Œ!
};

class Derived : public Base {
private:
    int* data;
public:
    Derived() { data = new int[1000]; }
    ~Derived() { 
        delete[] data;  // ์ด๊ฒŒ ํ˜ธ์ถœ ์•ˆ ๋จ!
        cout << "Derived ์†Œ๋ฉธ" << endl; 
    }
};

Base* ptr = new Derived();
delete ptr;  // ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐœ์ƒ! ๐Ÿ’ฅ

// ํ•ด๊ฒฐ์ฑ…
class Base {
public:
    virtual ~Base() { cout << "Base ์†Œ๋ฉธ" << endl; }  // virtual ์ถ”๊ฐ€!
};

โŒ ์‹ค์ˆ˜ 2: ์Šฌ๋ผ์ด์‹ฑ ๋ฌธ์ œ

// ๋ฌธ์ œ ์ฝ”๋“œ
class Animal {
public:
    virtual void speak() { cout << "๋™๋ฌผ ์†Œ๋ฆฌ" << endl; }
};

class Dog : public Animal {
public:
    void speak() override { cout << "๋ฉ๋ฉ!" << endl; }
};

void makeSound(Animal animal) {  // ๊ฐ’์œผ๋กœ ์ „๋‹ฌ! ์œ„ํ—˜!
    animal.speak();
}

Dog dog;
makeSound(dog);  // "๋™๋ฌผ ์†Œ๋ฆฌ" ์ถœ๋ ฅ (์Šฌ๋ผ์ด์‹ฑ ๋ฐœ์ƒ!)

// ํ•ด๊ฒฐ์ฑ…: ํฌ์ธํ„ฐ๋‚˜ ์ฐธ์กฐ ์‚ฌ์šฉ
void makeSound(Animal& animal) {  // ์ฐธ์กฐ๋กœ ์ „๋‹ฌ!
    animal.speak();
}

makeSound(dog);  // "๋ฉ๋ฉ!" ์ถœ๋ ฅ โœ…

โŒ ์‹ค์ˆ˜ 3: ์ˆœ์ˆ˜ ๊ฐ€์ƒํ•จ์ˆ˜ ๋ฏธ๊ตฌํ˜„

// ๋ฌธ์ œ ์ฝ”๋“œ
class Shape {
public:
    virtual double getArea() const = 0;
    virtual void draw() const = 0;
};

class Circle : public Shape {
public:
    double getArea() const override { return 3.14 * r * r; }
    // draw()๋ฅผ ๊ตฌํ˜„ ์•ˆ ํ•จ!
};

Circle c;  // ์ปดํŒŒ์ผ ์—๋Ÿฌ! ์ถ”์ƒํด๋ž˜์Šค๋Š” ์ธ์Šคํ„ด์Šคํ™” ๋ถˆ๊ฐ€

// ํ•ด๊ฒฐ์ฑ…: ๋ชจ๋“  ์ˆœ์ˆ˜ ๊ฐ€์ƒํ•จ์ˆ˜ ๊ตฌํ˜„
class Circle : public Shape {
public:
    double getArea() const override { return 3.14 * r * r; }
    void draw() const override { cout << "์› ๊ทธ๋ฆฌ๊ธฐ" << endl; }  // ๊ตฌํ˜„!
};

โŒ ์‹ค์ˆ˜ 4: ๋‹ค์ค‘ ์ƒ์† ๋‹ค์ด์•„๋ชฌ๋“œ ๋ฌธ์ œ

// ๋ฌธ์ œ ์ฝ”๋“œ
class A {
public:
    int value;
};

class B : public A { };
class C : public A { };
class D : public B, public C { };  // ๋‹ค์ด์•„๋ชฌ๋“œ ์ƒ์†!

D d;
d.value = 10;  // ์ปดํŒŒ์ผ ์—๋Ÿฌ! value๊ฐ€ ๋ชจํ˜ธํ•จ

// ํ•ด๊ฒฐ์ฑ… 1: ๊ฐ€์ƒ ์ƒ์†
class B : virtual public A { };
class C : virtual public A { };
class D : public B, public C { };  // ์ด์ œ OK!

// ํ•ด๊ฒฐ์ฑ… 2: ์ธํ„ฐํŽ˜์ด์Šค ์‚ฌ์šฉ (๋” ๊ถŒ์žฅ)
class IB {
public:
    virtual void funcB() = 0;
};

class IC {
public:
    virtual void funcC() = 0;
};

class D : public IB, public IC {
    // ๊ฐ๊ฐ ๊ตฌํ˜„
};

โŒ ์‹ค์ˆ˜ 5: override ํ‚ค์›Œ๋“œ ์•ˆ ์“ฐ๊ธฐ

// ๋ฌธ์ œ ์ฝ”๋“œ
class Base {
public:
    virtual void func(int x) { }
};

class Derived : public Base {
public:
    void func(double x) { }  // ์˜ค๋ฒ„๋ผ์ด๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ ์˜ค๋ฒ„๋กœ๋“œ!
};

Base* ptr = new Derived();
ptr->func(10);  // Base::func ํ˜ธ์ถœ๋จ! ๐Ÿ˜ฑ

// ํ•ด๊ฒฐ์ฑ…: override ํ‚ค์›Œ๋“œ ์‚ฌ์šฉ
class Derived : public Base {
public:
    void func(double x) override { }  // ์ปดํŒŒ์ผ ์—๋Ÿฌ ๋ฐœ์ƒ! ๐Ÿ‘
    // ์˜ฌ๋ฐ”๋ฅธ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋กœ ์ˆ˜์ •
    void func(int x) override { }  // ์ด์ œ OK!
};
๐ŸŽฏ ํ•ต์‹ฌ ๊ตํ›ˆ

1๏ธโƒฃ ํ•ญ์ƒ ๊ฐ€์ƒ ์†Œ๋ฉธ์ž๋ฅผ ์‚ฌ์šฉํ•˜์ž
2๏ธโƒฃ ๋‹คํ˜•์„ฑ์ด ํ•„์š”ํ•˜๋ฉด ํฌ์ธํ„ฐ๋‚˜ ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜์ž
3๏ธโƒฃ override ํ‚ค์›Œ๋“œ๋กœ ์‹ค์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•˜์ž
4๏ธโƒฃ ๋‹ค์ค‘ ์ƒ์†์€ ์‹ ์ค‘ํ•˜๊ฒŒ, ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์„ ํ˜ธํ•˜์ž
5๏ธโƒฃ ์ปดํŒŒ์ผ๋Ÿฌ ๊ฒฝ๊ณ ๋ฅผ ๋ฌด์‹œํ•˜์ง€ ๋ง์ž!

๐ŸŒŸ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

์™€, ์—ฌ๊ธฐ๊นŒ์ง€ ์ •๋ง ๊ธด ์—ฌ์ •์ด์—ˆ์–ด! ๐ŸŽ‰ C++์˜ ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ, ๋‹คํ˜•์„ฑ, ๊ฐ€์ƒํ•จ์ˆ˜, ์ถ”์ƒํด๋ž˜์Šค, ๊ทธ๋ฆฌ๊ณ  ๋‹ค์–‘ํ•œ ๋””์ž์ธ ํŒจํ„ด๊นŒ์ง€ ์ „๋ถ€ ๋‹ค๋ค˜์–ด.

์ด ๋ชจ๋“  ๊ฐœ๋…๋“ค์ด ์ฒ˜์Œ์—๋Š” ์–ด๋ ต๊ฒŒ ๋А๊ปด์งˆ ์ˆ˜ ์žˆ์–ด. ํ•˜์ง€๋งŒ ๊ฑฑ์ •ํ•˜์ง€ ๋งˆ! ๋‚˜๋„ ์ฒ˜์Œ์—” ํ—ท๊ฐˆ๋ ธ๊ฑฐ๋“ . ์ค‘์š”ํ•œ ๊ฑด ๊พธ์ค€ํžˆ ์—ฐ์Šตํ•˜๊ณ , ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•ด๋ณด๋Š” ๊ฑฐ์•ผ. ๐Ÿ’ช

๐ŸŽฏ ๊ธฐ์–ตํ•ด์•ผ ํ•  ํ•ต์‹ฌ ํฌ์ธํŠธ
  • โœ… ๋‹คํ˜•์„ฑ์€ C++์˜ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜
  • โœ… ๊ฐ€์ƒํ•จ์ˆ˜๋กœ ๋Ÿฐํƒ€์ž„ ๋‹คํ˜•์„ฑ์„ ๊ตฌํ˜„
  • โœ… ์ถ”์ƒํด๋ž˜์Šค๋กœ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜
  • โœ… ๋””์ž์ธ ํŒจํ„ด์€ ๊ฒ€์ฆ๋œ ํ•ด๊ฒฐ์ฑ…
  • โœ… SOLID ์›์น™์„ ๋”ฐ๋ฅด๋ฉด ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฌ์›Œ์ง
  • โœ… ์‹ค๋ฌด ๊ฒฝํ—˜์ด ๊ฐ€์žฅ ์ค‘์š”!
์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค๊ณผ ์ฝ”๋“œ๋ฅผ ๊ณต์œ ํ•˜๊ณ  ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›๋Š” ๊ฒƒ๋„ ์ •๋ง ์ข‹์€ ํ•™์Šต ๋ฐฉ๋ฒ•์ด์•ผ. ํ˜ผ์ž ๊ณต๋ถ€ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ๋นจ๋ฆฌ ์„ฑ์žฅํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ ! ๐Ÿš€

ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ๊ฒฐ๊ตญ ๋ฌธ์ œ ํ•ด๊ฒฐ์ด์•ผ. ๊ฐ์ฒด์ง€ํ–ฅ๊ณผ ๋””์ž์ธ ํŒจํ„ด์€ ๊ทธ ๋ฌธ์ œ๋ฅผ ๋” ์šฐ์•„ํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ํ•ด๊ฒฐํ•˜๋Š” ๋„๊ตฌ์ผ ๋ฟ์ด์•ผ. ๋„๊ตฌ๋ฅผ ์ž˜ ๋‹ค๋ฃจ๋Š” ๊ฒƒ๋„ ์ค‘์š”ํ•˜์ง€๋งŒ, ์–ด๋–ค ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ• ์ง€, ์™œ ์ด ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์ดํ•ดํ•˜๋Š” ๊ฒŒ ๋” ์ค‘์š”ํ•ด! ๐ŸŽฏ

์•ž์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ์ด๋ ‡๊ฒŒ ์ƒ๊ฐํ•ด๋ด:
โ€ข "์ด ํด๋ž˜์Šค๋Š” ํ•˜๋‚˜์˜ ์ฑ…์ž„๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ๋‚˜?" (SRP)
โ€ข "์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๋•Œ ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•˜๋‚˜?" (OCP)
โ€ข "์ด ํŒจํ„ด์ด ์ •๋ง ํ•„์š”ํ•œ๊ฐ€, ์•„๋‹ˆ๋ฉด ๊ณผ๋„ํ•œ ์„ค๊ณ„์ธ๊ฐ€?"
โ€ข "๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ด ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šธ๊นŒ?"

์ข‹์€ ์ฝ”๋“œ๋Š” ํ•˜๋ฃจ์•„์นจ์— ๋งŒ๋“ค์–ด์ง€์ง€ ์•Š์•„. ๊ณ„์† ๋ฐฐ์šฐ๊ณ , ์‹คํ—˜ํ•˜๊ณ , ๋ฆฌํŒฉํ† ๋งํ•˜๋ฉด์„œ ์ ์  ๋‚˜์•„์ง€๋Š” ๊ฑฐ์•ผ. ์‹ค์ˆ˜ํ•ด๋„ ๊ดœ์ฐฎ์•„! ๊ทธ๊ฒŒ ๋ฐฐ์šฐ๋Š” ๊ณผ์ •์ด๋‹ˆ๊นŒ. ๐Ÿ˜Š

๐Ÿ’ก ๋‹ค์Œ ๋‹จ๊ณ„ ์ถ”์ฒœ

1๏ธโƒฃ ์ž‘์€ ํ”„๋กœ์ ํŠธ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์„œ ๋ฐฐ์šด ํŒจํ„ด๋“ค์„ ์ ์šฉํ•ด๋ณด์ž
2๏ธโƒฃ ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ์˜ ์ฝ”๋“œ๋ฅผ ์ฝ์–ด๋ณด์ž (ํŠนํžˆ ๊ฒŒ์ž„ ์—”์ง„!)
3๏ธโƒฃ ์ฝ”๋“œ ๋ฆฌ๋ทฐ๋ฅผ ๋ฐ›๊ณ  ํ”ผ๋“œ๋ฐฑ์„ ์ ๊ทน ์ˆ˜์šฉํ•˜์ž
4๏ธโƒฃ ์žฌ๋Šฅ๋„ท์—์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•˜๋ฉฐ ์‹ค๋ ฅ์„ ํ‚ค์šฐ์ž
5๏ธโƒฃ ๊ณ„์† ์ƒˆ๋กœ์šด ๊ฒƒ์„ ๋ฐฐ์šฐ๊ณ  ๋„์ „ํ•˜์ž!
์ž, ์ด์ œ ๋„ˆ๋„ C++ ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ๊ณ ์ˆ˜๊ฐ€ ๋  ์ค€๋น„๊ฐ€ ๋์–ด! ๐ŸŽ“ ์ด ๊ธ€์ด ๋„์›€์ด ๋๋‹ค๋ฉด ์ •๋ง ๊ธฐ์  ๊ฒƒ ๊ฐ™์•„. ๊ถ๊ธˆํ•œ ์ ์ด ์žˆ์œผ๋ฉด ์–ธ์ œ๋“  ๋ฌผ์–ด๋ด. ์šฐ๋ฆฌ ๋ชจ๋‘ ํ•จ๊ป˜ ์„ฑ์žฅํ•˜๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์ž! ๐ŸŒฑ

ํ–‰๋ณตํ•œ ์ฝ”๋”ฉ ๋˜๊ธธ ๋ฐ”๋ผ! Happy Coding! ๐Ÿ’ปโœจ
๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0