ํฌ์ŠคํŠธ

CS โ€” oop

CS โ€” oop

๐Ÿ“• 04/12 - OOP (๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ) ์ •๋ฆฌ

Notion ์›๋ณธ: https://www.notion.so/340f77b24d2f81808ae2d58e64d8dc2e ๋ถ€๋ชจ: ์ž๋ฃŒ โ†’ Cs ๋ฉด์ ‘์ค€๋น„ โ†’ cs ์ฃผ์ œ

๋ชจ์˜๋ฉด์ ‘ ๋‹ต๋ณ€ โ€” โ€œOOP๋ž€ ๋ฌด์—‡์ธ๊ฐ€์š”?โ€

OOP, ์ฆ‰ ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ํ”„๋กœ๊ทธ๋žจ์„ ๊ฐ์ฒด(Object) ๋‹จ์œ„๋กœ ๊ตฌ์„ฑํ•˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํŒจ๋Ÿฌ๋‹ค์ž„์ž…๋‹ˆ๋‹ค. ํ˜„์‹ค ์„ธ๊ณ„์˜ ์‚ฌ๋ฌผ์ฒ˜๋Ÿผ, ๋ฐ์ดํ„ฐ(์†์„ฑ)์™€ ํ–‰๋™(๋ฉ”์„œ๋“œ)์„ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ๋ฌถ์–ด ๊ด€๋ฆฌํ•˜๋ฉฐ, ํด๋ž˜์Šค๋Š” ์„ค๊ณ„๋„, ๊ฐ์ฒด๋Š” ๊ทธ ์„ค๊ณ„๋„๋กœ ๋งŒ๋“  ์‹ค์ฒด์ž…๋‹ˆ๋‹ค.

OOP๋Š” 4๊ฐ€์ง€ ํ•ต์‹ฌ ์›์น™์œผ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.

  • ์ฒซ์งธ, ์บก์Аํ™”์ž…๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ์™€ ๋ฉ”์„œ๋“œ๋ฅผ ํ•˜๋‚˜์˜ ํด๋ž˜์Šค๋กœ ๋ฌถ๊ณ , private ์ ‘๊ทผ ์ง€์ •์ž๋กœ ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ์ˆจ๊ฒจ ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ๋‘˜์งธ, ์ƒ์†์ž…๋‹ˆ๋‹ค. ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ์†์„ฑ๊ณผ ๋ฉ”์„œ๋“œ๋ฅผ ์ž์‹ ํด๋ž˜์Šค๊ฐ€ ๋ฌผ๋ ค๋ฐ›์•„ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค.
  • ์…‹์งธ, ๋‹คํ˜•์„ฑ์ž…๋‹ˆ๋‹ค. ๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋‹ค๋ฅธ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋Šฅ๋ ฅ์œผ๋กœ, C++์—์„œ๋Š” ๊ฐ€์ƒ ํ•จ์ˆ˜(virtual)์™€ ์˜ค๋ฒ„๋ผ์ด๋”ฉ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋„ท์งธ, ์ถ”์ƒํ™”์ž…๋‹ˆ๋‹ค. ๋ณต์žกํ•œ ๊ตฌํ˜„ ์„ธ๋ถ€์‚ฌํ•ญ์„ ์ˆจ๊ธฐ๊ณ  ํ•ต์‹ฌ ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์™ธ๋ถ€์— ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค. C++์—์„œ๋Š” ์ˆœ์ˆ˜ ๊ฐ€์ƒ ํ•จ์ˆ˜(= 0)๋กœ ์ถ”์ƒ ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

์‹ค์ œ ์˜ˆ์‹œ๋กœ, ์–ธ๋ฆฌ์–ผ ์—”์ง„์˜ AActor๋‚˜ UObject ๋ชจ๋‘ ์ด OOP ์›์น™์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์„ค๊ณ„๋˜์–ด ์žˆ์–ด, BeginPlay()์™€ Tick() ๊ฐ™์€ ๊ฐ€์ƒ ํ•จ์ˆ˜๋ฅผ ์žฌ์ •์˜ํ•ด ๋‹คํ˜•์„ฑ์„ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๊ฐœ๋…

  • ๊ฐ์ฒด (Object) โ€” ๋ฐ์ดํ„ฐ(์†์„ฑ)์™€ ํ–‰๋™(๋ฉ”์„œ๋“œ)์„ ๋ฌถ์€ ๋‹จ์œ„
  • ํด๋ž˜์Šค (Class) โ€” ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์„ค๊ณ„๋„ (๋ถ•์–ด๋นต ํ‹€)
  • ์ธ์Šคํ„ด์Šค (Instance) โ€” ํด๋ž˜์Šค์—์„œ ์ƒ์„ฑ๋œ ์‹ค์ฒด (๋ถ•์–ด๋นต)
  • ํŒจ๋Ÿฌ๋‹ค์ž„ (Paradigm) โ€” ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๋ฐ”๋ผ๋ณด๋Š” ๋ฐฉ์‹/๊ด€์ 
  • ์†์„ฑ (Attribute) โ€” ๊ฐ์ฒด๊ฐ€ ๊ฐ€์ง€๋Š” ๋ฐ์ดํ„ฐ (๋ฉค๋ฒ„ ๋ณ€์ˆ˜)
  • ๋ฉ”์„œ๋“œ (Method) โ€” ๊ฐ์ฒด๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ํ–‰๋™ (๋ฉค๋ฒ„ ํ•จ์ˆ˜)

4๋Œ€ ์›์น™

์›์น™ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ
์บก์Аํ™” (Encapsulation)private, ์ ‘๊ทผ ์ง€์ •์ž, ์ •๋ณด ์€๋‹‰, ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ, Getter/Setter
์ƒ์† (Inheritance)IS-A ๊ด€๊ณ„, ๋ถ€๋ชจ/์ž์‹ ํด๋ž˜์Šค, ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ, virtual, override
๋‹คํ˜•์„ฑ (Polymorphism)๊ฐ€์ƒ ํ•จ์ˆ˜(virtual), ์˜ค๋ฒ„๋ผ์ด๋”ฉ, ๋Ÿฐํƒ€์ž„ ๊ฒฐ์ •, vtable, ๋™์  ๋””์ŠคํŒจ์น˜
์ถ”์ƒํ™” (Abstraction)์ˆœ์ˆ˜ ๊ฐ€์ƒ ํ•จ์ˆ˜(= 0), ์ถ”์ƒ ํด๋ž˜์Šค, ์ธํ„ฐํŽ˜์ด์Šค, ๊ณ„์•ฝ(Contract)

์–ธ๋ฆฌ์–ผ ์—ฐ๊ฒฐ ํ‚ค์›Œ๋“œ

  • AActor / UObject โ€” ์–ธ๋ฆฌ์–ผ์˜ ํ•ต์‹ฌ ํด๋ž˜์Šค, OOP ๊ธฐ๋ฐ˜ ์„ค๊ณ„
  • BeginPlay() / Tick() โ€” ๊ฐ€์ƒ ํ•จ์ˆ˜ โ†’ ๋‹คํ˜•์„ฑ ์‹ค์ œ ํ™œ์šฉ ์˜ˆ์‹œ
  • UPROPERTY() โ€” ์บก์Аํ™”์˜ ์—ฐ์žฅ์„  (์—๋””ํ„ฐ ๋…ธ์ถœ ๋ฒ”์œ„ ์ œ์–ด)
  • IInterface โ€” ์–ธ๋ฆฌ์–ผ์˜ ์ธํ„ฐํŽ˜์ด์Šค ํŒจํ„ด (์ถ”์ƒํ™”)

new๋Š” ํ•จ์ˆ˜์ธ๊ฐ€?

new๋Š” ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ C++ ์—ฐ์‚ฐ์ž(operator)์ž…๋‹ˆ๋‹ค. ๋‹จ, ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์„ ์œ„ํ•ด operator new๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. operator new๋Š” ์˜ค๋ฒ„๋กœ๋”ฉ ๊ฐ€๋Šฅํ•œ ํ•จ์ˆ˜์ด๊ณ , new ํ‘œํ˜„์‹์€ ๊ทธ๊ฒƒ์„ ๊ฐ์‹ธ๋Š” ์—ฐ์‚ฐ์ž์ž…๋‹ˆ๋‹ค.

new ํ‘œํ˜„์‹์˜ ์‹คํ–‰ ๋‹จ๊ณ„

1
2
3
4
5
Player* p = new Player();
// ๋‚ด๋ถ€์ ์œผ๋กœ:
void* mem = operator new(sizeof(Player));  // 1. ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น
new(mem) Player();                          // 2. ์ƒ์„ฑ์ž ํ˜ธ์ถœ (placement new)
Player* p = static_cast<Player*>(mem);      // 3. ํƒ€์ž… ํฌ์ธํ„ฐ๋กœ ๋ฐ˜ํ™˜

operator new vs new ํ‘œํ˜„์‹

ย new ํ‘œํ˜„์‹operator new
๋ถ„๋ฅ˜์—ฐ์‚ฐ์žํ•จ์ˆ˜
์—ญํ• ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น + ์ƒ์„ฑ์ž ํ˜ธ์ถœ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น๋งŒ
์˜ค๋ฒ„๋กœ๋”ฉ๋ถˆ๊ฐ€๊ฐ€๋Šฅ
์ง์ ‘ ํ˜ธ์ถœnew T()operator new(sizeof(T))

๊ฐ์ฒด(Object)๋ž€?

1
2
3
4
5
6
7
8
9
10
11
12
13
// ํด๋ž˜์Šค = ์„ค๊ณ„๋„ (๋ถ•์–ด๋นต ํ‹€)
class Player {
public:
    string name;   // ์†์„ฑ
    int health;

    void Attack() { }  // ํ–‰๋™
    void Move()   { }
};

// ๊ฐ์ฒด = ์ธ์Šคํ„ด์Šค (๋ถ•์–ด๋นต)
Player p1;
Player p2;  // p2๋Š” ๋ณ„๊ฐœ์˜ ๊ฐ์ฒด โ€” ๊ฐ™์€ ์„ค๊ณ„๋„, ๋‹ค๋ฅธ ์‹ค์ฒด

์บก์Аํ™” (Encapsulation)

์บก์Аํ™”๋Š” ๋ฐ์ดํ„ฐ(๋ฉค๋ฒ„ ๋ณ€์ˆ˜)์™€ ๋ฉ”์„œ๋“œ(๋ฉค๋ฒ„ ํ•จ์ˆ˜)๋ฅผ ํ•˜๋‚˜์˜ ํด๋ž˜์Šค๋กœ ๋ฌถ๊ณ , ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ์™ธ๋ถ€์—์„œ ์ง์ ‘ ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•˜๋„๋ก ์ •๋ณด ์€๋‹‰(Information Hiding)ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ ‘๊ทผ ์ง€์ •์ž(public / protected / private)๋กœ ์™ธ๋ถ€ ๋…ธ์ถœ ๋ฒ”์œ„๋ฅผ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค.

์ ‘๊ทผ ์ง€์ •์ž

  • public: ํด๋ž˜์Šค ๋‚ด๋ถ€ + ์™ธ๋ถ€ + ํŒŒ์ƒ ํด๋ž˜์Šค โ€” ์™ธ๋ถ€ ์ธํ„ฐํŽ˜์ด์Šค
  • protected: ํด๋ž˜์Šค ๋‚ด๋ถ€ + ํŒŒ์ƒ ํด๋ž˜์Šค โ€” ํŒŒ์ƒ ํด๋ž˜์Šค ์ „์šฉ
  • private: ํด๋ž˜์Šค ๋‚ด๋ถ€๋งŒ โ€” ๊ตฌํ˜„ ์„ธ๋ถ€์‚ฌํ•ญ ์€๋‹‰
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class BankAccount {
private:
    double balance;

public:
    void Deposit(double amount) {
        if (amount > 0)
            balance += amount;
    }
    void Withdraw(double amount) {
        if (amount > 0 && amount <= balance)
            balance -= amount;
    }
    double GetBalance() const { return balance; }
};

BankAccount acc;
// acc.balance = -500;   // ERROR
acc.Deposit(1000);       // OK โ€” ๊ฒ€์ฆ ํ›„ ์•ˆ์ „ ์ฒ˜๋ฆฌ

์ƒ์† (Inheritance)

์ƒ์†์€ ๊ธฐ์กด ํด๋ž˜์Šค(๋ถ€๋ชจ/๊ธฐ๋ฐ˜ ํด๋ž˜์Šค)์˜ ์†์„ฑ๊ณผ ๋ฉ”์„œ๋“œ๋ฅผ ์ƒˆ ํด๋ž˜์Šค(์ž์‹/ํŒŒ์ƒ ํด๋ž˜์Šค)๊ฐ€ ๋ฌผ๋ ค๋ฐ›์•„ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด๊ณ , IS-A ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค.

IS-A vs HAS-A

  • IS-A: public ์ƒ์† (Dog IS-A Animal)
  • HAS-A: ์ปดํฌ์ง€์…˜ or private ์ƒ์† (Car HAS-A Engine)

์ƒ์† ๋ฐฉ์‹๋ณ„ ์ ‘๊ทผ ์ง€์ •์ž ๋ณ€ํ™˜

๊ธฐ๋ณธ ํด๋ž˜์Šค ๋ฉค๋ฒ„public ์ƒ์†protected ์ƒ์†private ์ƒ์†
publicโ†’ publicโ†’ protectedโ†’ private
protectedโ†’ protectedโ†’ protectedโ†’ private
private์ ‘๊ทผ ๋ถˆ๊ฐ€์ ‘๊ทผ ๋ถˆ๊ฐ€์ ‘๊ทผ ๋ถˆ๊ฐ€

๊ฐ€์ƒ ํ•จ์ˆ˜ + override

1
2
3
4
5
6
7
8
9
10
class Shape {
public:
    virtual void Draw() = 0;   // ์ˆœ์ˆ˜ ๊ฐ€์ƒ ํ•จ์ˆ˜
    virtual ~Shape() { }       // ๊ฐ€์ƒ ์†Œ๋ฉธ์ž ํ•„์ˆ˜!
};

class Circle : public Shape {
public:
    void Draw() override { cout << "์› ๊ทธ๋ฆฌ๊ธฐ\n"; }
};

๋ณต๊ธฐ:

  • IS-A = public ์ƒ์†, HAS-A = ์ปดํฌ์ง€์…˜
  • virtual ์—†์œผ๋ฉด ํŒŒ์ƒ ํด๋ž˜์Šค์—์„œ ์žฌ์ •์˜ํ•ด๋„ ๋‹คํ˜•์„ฑ ๋ถˆ๊ฐ€
  • ๊ฐ€์ƒ ์†Œ๋ฉธ์ž ์—†์œผ๋ฉด ํŒŒ์ƒ ํด๋ž˜์Šค ์†Œ๋ฉธ์ž ๋ฏธํ˜ธ์ถœ โ†’ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜
  • override ํ‚ค์›Œ๋“œ๋กœ ์žฌ์ •์˜ ๋ช…์‹œ โ†’ ์˜คํƒ€๋ฅผ ์ปดํŒŒ์ผ ์—๋Ÿฌ๋กœ

๋‹คํ˜•์„ฑ (Polymorphism)

๋‹คํ˜•์„ฑ์€ ๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค(ํ•จ์ˆ˜ ์ด๋ฆ„)๋กœ ๋‹ค๋ฅธ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋Šฅ๋ ฅ์ž…๋‹ˆ๋‹ค. C++์—์„œ๋Š” ์ปดํŒŒ์ผ ํƒ€์ž„ ๋‹คํ˜•์„ฑ(์˜ค๋ฒ„๋กœ๋”ฉ, ํ…œํ”Œ๋ฆฟ)๊ณผ ๋Ÿฐํƒ€์ž„ ๋‹คํ˜•์„ฑ(๊ฐ€์ƒ ํ•จ์ˆ˜, ์˜ค๋ฒ„๋ผ์ด๋”ฉ)์œผ๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค.

์ปดํŒŒ์ผ ํƒ€์ž„ vs ๋Ÿฐํƒ€์ž„

ย ์ปดํŒŒ์ผ ํƒ€์ž„๋Ÿฐํƒ€์ž„
๊ตฌํ˜„ ๋ฐฉ๋ฒ•ํ•จ์ˆ˜ ์˜ค๋ฒ„๋กœ๋”ฉ, ํ…œํ”Œ๋ฆฟ๊ฐ€์ƒ ํ•จ์ˆ˜, ์˜ค๋ฒ„๋ผ์ด๋”ฉ
๊ฒฐ์ • ์‹œ์ ์ปดํŒŒ์ผ ์‹œ๋Ÿฐํƒ€์ž„ ์‹œ (vtable)
์„ฑ๋Šฅ๋น ๋ฆ„ (์ธ๋ผ์ธ ๊ฐ€๋Šฅ)vtable ์ฐธ์กฐ ๋น„์šฉ ๋ฐœ์ƒ
์œ ์—ฐ์„ฑ๋‚ฎ์Œ๋†’์Œ (๋™์  ๋””์ŠคํŒจ์น˜)

ํ•จ์ˆ˜ ์˜ค๋ฒ„๋กœ๋”ฉ (์ปดํŒŒ์ผ ํƒ€์ž„)

1
2
3
4
5
6
7
void Attack(int damage)          { cout << "๋ฌผ๋ฆฌ ๊ณต๊ฒฉ: " << damage; }
void Attack(float damage)        { cout << "๋งˆ๋ฒ• ๊ณต๊ฒฉ: " << damage; }
void Attack(int damage, int cnt) { cout << "์—ฐ์† ๊ณต๊ฒฉ: " << damage * cnt; }

Attack(50);        // Attack(int)
Attack(30.5f);     // Attack(float)
Attack(20, 3);     // Attack(int, int)

๊ฐ€์ƒ ํ•จ์ˆ˜ (๋Ÿฐํƒ€์ž„)

1
2
3
4
5
6
7
8
9
10
11
12
class Shape {
public:
    virtual void Draw() { cout << "๋„ํ˜•\n"; }
    virtual ~Shape() { }
};

class Circle   : public Shape { public: void Draw() override { cout << "์›\n"; } };
class Triangle : public Shape { public: void Draw() override { cout << "์‚ผ๊ฐํ˜•\n"; } };

Shape* shapes[] = { new Circle(), new Triangle() };
for (Shape* s : shapes)
    s->Draw();  // "์›" โ†’ "์‚ผ๊ฐํ˜•"

vtable ๋™์ž‘

  • ๊ฐ€์ƒ ํ•จ์ˆ˜ ์žˆ์œผ๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ vtable ์ž๋™ ์ƒ์„ฑ
  • ๊ฐ์ฒด๋Š” vptr(vtable ํฌ์ธํ„ฐ)์„ ์ˆจ๊ฒจ์„œ ๋ณด์œ 
  • s->Draw() ํ˜ธ์ถœ ์‹œ: vptr ์ฝ๊ธฐ โ†’ vtable์—์„œ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ ์ฐพ๊ธฐ โ†’ ๊ฐ„์ ‘ ํ˜ธ์ถœ
  • ์ด๊ฒƒ์ด ๋™์  ๋””์ŠคํŒจ์น˜(Dynamic Dispatch)

์ถ”์ƒํ™” (Abstraction)

์ถ”์ƒํ™”๋Š” ๋ณต์žกํ•œ ๊ตฌํ˜„ ์„ธ๋ถ€์‚ฌํ•ญ์„ ์ˆจ๊ธฐ๊ณ  ํ•ต์‹ฌ ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์™ธ๋ถ€์— ๋…ธ์ถœํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. C++์—์„œ๋Š” ์ˆœ์ˆ˜ ๊ฐ€์ƒ ํ•จ์ˆ˜(= 0)๋กœ ์ถ”์ƒ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

์ถ”์ƒ ํด๋ž˜์Šค vs ์ธํ„ฐํŽ˜์ด์Šค

ย ์ถ”์ƒ ํด๋ž˜์Šค์ธํ„ฐํŽ˜์ด์Šค
C++ ๊ตฌํ˜„์ˆœ์ˆ˜ ๊ฐ€์ƒ ํ•จ์ˆ˜ 1๊ฐœ ์ด์ƒ๋ชจ๋“  ํ•จ์ˆ˜๊ฐ€ ์ˆœ์ˆ˜ ๊ฐ€์ƒ ํ•จ์ˆ˜
๋ฉค๋ฒ„ ๋ณ€์ˆ˜๊ฐ€์งˆ ์ˆ˜ ์žˆ์Œ์—†์Œ (๊ถŒ์žฅ)
์ธ์Šคํ„ด์Šคํ™”๋ถˆ๊ฐ€๋ถˆ๊ฐ€
์šฉ๋„๊ณตํ†ต ๊ตฌํ˜„ + ์ผ๋ถ€ ์ถ”์ƒํ™”๊ณ„์•ฝ(Contract)๋งŒ ์ •์˜
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Animal {
public:
    virtual void MakeSound() = 0;  // ์ˆœ์ˆ˜ ๊ฐ€์ƒ ํ•จ์ˆ˜
    virtual ~Animal() { }
    void Breathe() { cout << "์ˆจ์‰ฌ๊ธฐ\n"; }
};

class Dog : public Animal {
public:
    void MakeSound() override { cout << "๋ฉ๋ฉ!\n"; }
};

// Animal a;   // ERROR โ€” ์ถ”์ƒ ํด๋ž˜์Šค๋Š” ์ธ์Šคํ„ด์Šคํ™” ๋ถˆ๊ฐ€
Dog d;
d.MakeSound(); // "๋ฉ๋ฉ!"

๋‹ค์ค‘ ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class IAttackable {
public:
    virtual void Attack() = 0;
    virtual int  GetDamage() const = 0;
    virtual ~IAttackable() { }
};

class IMovable {
public:
    virtual void Move(float x, float y) = 0;
    virtual ~IMovable() { }
};

class Player : public IAttackable, public IMovable {
public:
    void Attack() override           { }
    int  GetDamage() const override  { return 50; }
    void Move(float x, float y) override { }
};

OOP vs ์ ˆ์ฐจ์ง€ํ–ฅ ๋น„๊ต

ํ•ญ๋ชฉ์ ˆ์ฐจ์ง€ํ–ฅOOP
๊ตฌ์กฐ ๋‹จ์œ„ํ•จ์ˆ˜๊ฐ์ฒด
๋ฐ์ดํ„ฐ ์ ‘๊ทผ์ „์—ญ/๊ณต์œ  ์ง์ ‘ ์ ‘๊ทผ์บก์Аํ™”๋กœ ๋ณดํ˜ธ
์ฝ”๋“œ ์žฌ์‚ฌ์šฉํ•จ์ˆ˜ ์žฌ์‚ฌ์šฉ์ƒ์†ยท์ปดํฌ์ง€์…˜
์œ ์ง€๋ณด์ˆ˜๊ทœ๋ชจ ์ปค์งˆ์ˆ˜๋ก ์–ด๋ ค์›€์บก์Аํ™”๋กœ ๋ณ€๊ฒฝ ์˜ํ–ฅ ์ œํ•œ
์–ธ์–ด ์˜ˆ์‹œC, Pascal, FORTRANC++, Java, Python, C#
์ ํ•ฉ๋‹จ์ˆœ ์Šคํฌ๋ฆฝํŠธ๋Œ€๊ทœ๋ชจ ์‹œ์Šคํ…œ, ๊ฒŒ์ž„ ์—”์ง„

SOLID ์›์น™

SOLID๋Š” ์œ ์ง€๋ณด์ˆ˜ ๊ฐ€๋Šฅํ•œ OOP ์„ค๊ณ„๋ฅผ ์œ„ํ•œ 5๊ฐ€์ง€ ์›์น™์ž…๋‹ˆ๋‹ค. ๋กœ๋ฒ„ํŠธ C. ๋งˆํ‹ด์ด ์ •๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค.

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

SRP

1
2
3
4
5
6
7
8
9
10
11
// ๋‚˜์œ ์˜ˆ
class Player {
    void Move()     { }
    void SaveData() { }   // ๋‹ค๋ฅธ ์ฑ…์ž„!
    void Render()   { }   // ๋˜ ๋‹ค๋ฅธ ์ฑ…์ž„!
};

// ์ข‹์€ ์˜ˆ
class Player         { void Move()  { } };
class PlayerSaver    { void Save(const Player& p)   { } };
class PlayerRenderer { void Render(const Player& p) { } };

OCP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ๋‚˜์œ ์˜ˆ โ€” ์ƒˆ ๋ฌด๊ธฐ ์ถ”๊ฐ€ ์‹œ ๊ธฐ์กด ์ฝ”๋“œ ์ˆ˜์ •
void UseWeapon(string type) {
    if (type == "sword")     { }
    else if (type == "bow")  { }
}

// ์ข‹์€ ์˜ˆ โ€” ์ถ”์ƒํ™”๋กœ ํ™•์žฅ ๊ฐ€๋Šฅ
class IWeapon {
public:
    virtual void Use() = 0;
    virtual ~IWeapon() { }
};
class Sword : public IWeapon { public: void Use() override { } };
class Bow   : public IWeapon { public: void Use() override { } };

๋ณต๊ธฐ:

  • SRP: ํด๋ž˜์Šค ํ•˜๋‚˜ = ์ฑ…์ž„ ํ•˜๋‚˜
  • OCP: ๊ธฐ์กด ์ฝ”๋“œ ์ˆ˜์ • ์—†์ด ์ƒˆ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ (์ถ”์ƒํ™” ํ™œ์šฉ)
  • LSP: ๋ถ€๋ชจ ํƒ€์ž… ํฌ์ธํ„ฐ๋กœ ์ž์‹ ์‚ฌ์šฉ ์‹œ ๋™์ž‘์ด ์˜ˆ์ƒ๊ณผ ๊ฐ™์•„์•ผ ํ•จ
  • ISP: ๋šฑ๋šฑํ•œ ์ธํ„ฐํŽ˜์ด์Šค โ†’ ์ž‘์€ ์ธํ„ฐํŽ˜์ด์Šค ์—ฌ๋Ÿฌ ๊ฐœ๋กœ ๋ถ„๋ฆฌ
  • DIP: ๊ตฌ์ฒด ํด๋ž˜์Šค๊ฐ€ ์•„๋‹Œ ์ธํ„ฐํŽ˜์ด์Šค(์ถ”์ƒํ™”)์— ์˜์กด
  • ์–ธ๋ฆฌ์–ผ: IInterface, UActorComponent ๋ถ„๋ฆฌ ์„ค๊ณ„ = SOLID ์‹ค์ฒœ
์ด ๊ธฐ์‚ฌ๋Š” ์ €์ž‘๊ถŒ์ž์˜ CC BY 4.0 ๋ผ์ด์„ผ์Šค๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

ยฉ GoldBoll. ์ผ๋ถ€ ๊ถŒ๋ฆฌ ๋ณด์œ 

Powered by Jekyll with Chirpy theme

์ธ๊ธฐ ํƒœ๊ทธ