학습일지/C와 C++

C++ 객체 지향과 메모리 관리

Tsukino Ren 2026. 4. 3. 21:38

 

다형성

  • virtual 없으면 다형성이 안된다.
  • 포인터 타입이 아니라 실제 객체 타입 기준으로 실행된다

#include <iostream>
#include <vector>
using namespace std;

class Animal 
{
public:
    Animal() {}
    virtual ~Animal() {}
    virtual void speak()
    {
        cout << "'Animal' cannot make a sound.\n";
    }

};

class Dog :public Animal
{
    void speak()
    {
        cout << "Woof\n";
    }
};

class Cat :public Animal
{
    void speak()
    {
        cout << "Meow\n";
    }
};

int main() {
    vector<Animal*> zoo{ new Dog, new Cat, new Animal };
    for (auto p : zoo) p->speak(); // Woof / Meow / ???
    for (auto p : zoo) delete p;
}

 


깊은 복사

  • 새로운 메모리를 별도로 할당한 뒤 그 안에 값을 복사
  • 하나의 객체가 해제되도 다른 객체는 해제되지 않는다

 

#include <iostream>
using namespace std;

class IntPtr {
    int* ptr;
public:
    IntPtr(int val) {
        ptr = new int(val);
    }

    ~IntPtr() 
    {
        delete ptr;
        ptr = nullptr;
    }

    IntPtr(const IntPtr& other) 
    {
        if (this == &other)
        {
            return;
        }
        int* newPtr;

        newPtr = new int(*other.ptr);
        
        ptr = newPtr;
    }

    int getValue() const {
        return *ptr;
    }
};

int main() {
    IntPtr p1(10);
    IntPtr p2 = p1; // 복사 생성자 호출

    cout << p1.getValue() << "\n"; // 10
    cout << p2.getValue() << "\n"; // 10
}
복사 생성자에서는 자기 자신 비교가 일반적으로 필요하지 않다는 점도 배웠다
아래의 코드는 사용하지 않는다.
if (this == &other)
        {
            return;
        }

정리

  • 포인터 멤버를 가진 클래스는 기본 복사에만 맡기면 위험할 수 있다.
  • 깊은 복사를 위해서는 새로운 메모리를 직접 할당해야 한다.
  • 동적 할당을 사용했따면 소멸자까지 함께 고려해야 한다.
  • 복사 생성자는 객체가 복사되는 순간 호출된다.

마무리

다향성

  • 단순히 함수를 상속받는 것이 아닌 같은 인터페이스로 다른 동작을 수행할 수 있다는 점에서 객체지향 설계의 중요성을 체감할 수 있었다.

깊은 복사

  • C++에서 메모리 관리가 왜 중요한가를 알게 해주는 문제였다. 단순히 값이 잘 출력된다고 끝이 아니라, 객체가 복사되고 소멸되는 과정까지 함께 고려해야 안전한 코드가 된다는 점을 확인할 수 있었다.