C++ 기초부터 객체지향 프로그래밍까지: 실전 연습을 통한 접근법

C++ 언어 개요

C++은 1983년 벨 연구소에서 Bjarne Stroustrup에 의해 처음 개발된 프로그래밍 언어입니다. 이 언어는 C 언어를 기반으로 객체지향 프로그래밍 기능을 추가한 것이 특징입니다.

기본 구조

    
    #include <iostream>
    
    int main() {
        std::cout << "Hello, World!";
        return 0;
    }

위 예시는 C++ 프로그램의 기본 구조입니다. #include <iostream>는 표준 입력/출력에 관련된 기능을 사용할 수 있게 해주는 라이브러리를 포함하는 구문입니다. int main()은 프로그램의 시작점을 나타내는 main 함수를 정의하는 구문이며, std::cout을 통해 화면에 "Hello, World!"를 출력합니다.

객체지향 프로그래밍

C++는 객체지향 프로그래밍(OOP) 지원을 위해 클래스(class)라는 기능을 제공합니다. 클래스는 변수(멤버 변수)와 함수(멤버 함수)를 포함하는 사용자 정의 데이터 타입입니다.

    
    // 클래스의 정의
    class Dog {
    public:
        // 멤버 변수
        std::string name;
        int age;

        // 멤버 함수
        void bark() {
            std::cout << name << " says: Woof!" << std::endl;
        }
    };

    int main() {
        // 클래스의 인스턴스 생성
        Dog myDog;
        myDog.name = "Fido";
        myDog.age = 3;

        // 멤버 함수 호출
        myDog.bark();

        return 0;
    }

개발환경 설정

C++ 코드를 작성하고 실행하기 위한 개발환경을 설정하는 방법에 대해 알아보도록 하겠습니다.

C++ 컴파일러

먼저, C++ 코드를 컴파일하기 위한 컴파일러가 필요합니다. GCC(GNU Compiler Collection), Clang, Visual C++ 등 다양한 컴파일러가 있습니다.

GCC를 설치하는 예시는 다음과 같습니다. 아래 예시는 Linux 기반 시스템에서의 GCC 설치 방법입니다.


    sudo apt-get update
    sudo apt-get install build-essential

텍스트 에디터

코드 작성을 위한 텍스트 에디터가 필요합니다. Visual Studio Code, Sublime Text, Atom 등이 많이 사용되며, 이들은 모두 C++을 지원합니다.

통합 개발 환경 (IDE)

텍스트 에디터보다 더 많은 기능을 제공하는 통합 개발 환경(IDE)를 사용하는 것도 좋은 선택입니다. Visual Studio, Eclipse, CLion 등이 있습니다.

Visual Studio 설치


1. 비주얼 스튜디오 공식 홈페이지에 접속합니다.
2. 'Download Visual Studio' 버튼을 클릭하여 최신 버전의 Visual Studio Community를 다운로드합니다.
3. 다운로드한 설치파일을 실행하여 Visual Studio를 설치합니다. 
4. 설치 과정에서 'Desktop development with C++' 항목을 선택하여 C++ 개발을 위한 환경을 설치합니다.

헬로 월드 프로그램 컴파일 및 실행

환경 설정이 완료되었다면, 간단한 "Hello, World" 프로그램을 통해 환경 설정이 잘 되었는지 확인해봅니다.

    
    #include <iostream>
    int main() {
        std::cout << "Hello, World!";
        return 0;
    }

이 프로그램을 컴파일하고 실행하는 방법은 다음과 같습니다.


    g++ hello.cpp -o hello
    ./hello

C++ 기초 문법

3.1 변수와 데이터 타입

C++에서는 여러 종류의 데이터 타입을 제공하고 있습니다. 이에 따라 변수를 선언하고 사용합니다.

    
    int myNumber = 5;  // Integer (whole number)
    float myFloatNum = 5.99; // Floating point number
    double myDoubleNum = 9.98; // Floating point number
    char myLetter = 'D'; // Character
    bool myBoolean = true; // Boolean
    std::string myText = "Hello"; // String

3.2 연산자와 제어문

C++에서는 다양한 연산자를 제공합니다. 예를 들어, 산술 연산자, 비교 연산자, 논리 연산자 등이 있습니다. 특정 조건에 따라 프로그램의 흐름을 제어할 수 있는 제어문도 제공합니다. 예를 들어, if문, switch문, for문, while문 등이 있습니다.

       
    int x = 10;
    int y = 9;
    
    if (x > y) {
        std::cout << "x is greater than y";
    }

3.3 배열과 문자열

배열은 동일한 타입의 여러 변수를 저장하는 데이터 구조입니다. 문자열은 문자의 배열로 볼 수 있으며, C++에서는 string 클래스를 통해 문자열을 제공합니다.

    
    // 배열 선언
    int myNum[3] = {10, 20, 30};
    
    // 문자열 선언
    std::string myString = "Hello";

함수와 매개변수

함수의 정의

함수는 재사용 가능한 코드 블록으로, 특정 작업을 수행하거나 값을 계산하는데 사용됩니다. 함수는 이름, 매개변수 리스트 및 리턴 타입을 가집니다.

C++에서는 다음과 같이 함수를 정의합니다.


    int myFunction() {
        // function body
        // ...
        return 0;
    }

매개변수와 인자

매개변수(parameter)는 함수 선언시 명시되는 변수를 말하며, 함수 내에서 사용될 수 있습니다. 인자(argument)는 실제로 함수를 호출할 때 전달되는 값입니다.


    // "a" and "b" are parameters
    int addNumbers(int a, int b) {
        return a + b;
    }

    int main() {
        // "5" and "10" are arguments
        std::cout << addNumbers(5, 10);
        return 0;
    }

값에 의한 호출 vs 참조에 의한 호출

C++에서는 값을 직접 전달하는 값에 의한 호출(Call by Value)과 값을 직접 변경할 수 있도록 참조를 전달하는 참조에 의한 호출(Call by Reference) 두 가지 방식을 제공합니다.


    // Call by Value
    void changeValue(int myNum) {
        myNum += 5; // this will not affect the actual parameter
    }
  
    // Call by Reference
    void changeValueRef(int &myNum) {
        myNum += 5; // this will change the actual parameter
    }

객체지향 프로그래밍 기초

5.1 클래스와 객체

클래스는 객체를 만드는 틀로, 데이터와 함수를 한 데 묶은 복합 자료형입니다. 객체는 클래스의 인스턴스를 의미합니다. 다음은 C++에서의 클래스와 객체의 사용 예시입니다.


    // 클래스 선언
    class MyClass {
      public:  // Access specifier
        int myNum;  // Attribute
        std::string myString;  // Attribute
    };

    int main() {
        MyClass myObj;  // 객체 생성
        myObj.myNum = 15;  // Access attribute and set value
        myObj.myString = "Some text";  // Access attribute and set value

        // Print values
        std::cout << myObj.myNum;
        std::cout << myObj.myString;
    }

5.2 생성자와 소멸자

생성자는 객체가 생성될 때 자동으로 호출되는 함수로, 주로 객체의 초기화에 사용됩니다. 소멸자는 객체가 없어질 때 자동으로 호출되는 함수로, 주로 객체를 삭제하기 전에 필요한 정리 작업에 사용됩니다.

    
    class MyClass {
      public:
        // 생성자
        MyClass() {
            std::cout << "Constructor is called";
        }

        // 소멸자
        ~MyClass() {
            std::cout << "Destructor is called";
        }
    };

    int main() {
        MyClass obj;  // 생성자가 호출되고, 이후에 소멸자가 호출됩니다.
    }

객체지향 프로그래밍 확장

6.1 상속과 다형성

상속은 클래스 간의 계층 관계를 형성하여 코드를 재사용하고 관리하는 구조입니다. 하위 클래스는 상위 클래스의 모든 속성과 메서드를 상속받습니다.

다형성은 한 타입의 참조를 사용하여 여러 타입의 객체를 참조할 수 있게 하는 객체 지향 원칙입니다. 이를 통해 코드의 유연성과 확장성을 증가시킬 수 있습니다.


    // Base class
    class Animal {
      public:
        virtual void makeSound() { 
            std::cout << "The animal makes a sound"; 
        }
    };

    // Derived class
    class Dog: public Animal {
      public:
        void makeSound() { 
            std::cout << "The dog barks"; 
        }
    };

    int main() {
        Animal* animal1 = new Animal();
        Animal* animal2 = new Dog();

        animal1->makeSound();  // Outputs "The animal makes a sound"
        animal2->makeSound();  // Outputs "The dog barks"

        return 0;
    }

6.2 추상화와 캡슐화

추상화는 복잡한 시스템을 단순화하여 개별 동작을 쉽게 이해하고 사용할 수 있게 하는 기법입니다.

캡슐화는 데이터와 해당 데이터를 처리하는 함수를 하나로 묶어 외부의 접근을 제한하고, 오용을 방지하는 기법입니다.


    // Class with private data members and public methods
    class MyEncapsulatedClass {
      private:
        int myAttr;

      public:
        void setAttr(int a) {
            myAttr = a;
        }

        int getAttr() {
            return myAttr;
        }
    };

    int main() {
        MyEncapsulatedClass obj;
        obj.setAttr(5);
        std::cout << obj.getAttr();  // Outputs "5"
    }

7. C++ 표준 라이브러리 이해하기

C++ 표준 라이브러리는 프로그래밍에서 자주 필요한 기능을 제공해 주는 일련의 코드 모음입니다. 이 라이브러리는 C++ 표준에 의해 정의되며, 모든 C++ 컴파일러에 포함되어 있습니다. C++ 표준 라이브러리는 크게 표준 함수 라이브러리 (cstdlib 등), 객체 지향 라이브러리 (iostream, vector 등)로 나뉩니다.


    #include 
    #include 
    #include 

    int main() {
        // 표준 라이브러리 함수 사용
        std::string str = "Hello, world!";
        std::cout << str << std::endl;

        // 표준 라이브러리 컨테이너와 알고리즘 사용
        std::vector vec {1, 2, 3, 4, 5};
        for(auto i : vec) {
            std::cout << i << ' ';
        }

        return 0;
    }

이 코드는 표준 라이브러리에서 제공하는 문자열, 입출력 스트림, 벡터 등을 사용하고 있습니다. 또한 벡터의 모든 원소를 출력하는 데에 범위 기반 for문이라는 고수준 개념을 사용했습니다. 이 예제는 C++ 표준 라이브러리가 얼마나 강력하고 유용한지 보여줍니다.


8. 실습을 통한 C++ 응용

8.1 간단한 콘솔 프로그램 만들기

C++을 사용하여 간단한 콘솔 프로그램을 만드는 것은 C++의 기본적인 이해와 사용을 도울 수 있습니다.


    #include 
    #include 

    int main() {
        std::string input;
        std::cout << "Hello! What's your name?" << std::endl;
        getline(std::cin, input);
        std::cout << "Nice to meet you, " << input << "!" << std::endl;
        return 0;
    }

h3>8.2 파일 입출력을 활용한 데이터 관리

파일 입출력은 필수적인 프로그래밍 스킬로, 데이터의 영속성을 보장하고 외부 파일로부터 정보를 가져오거나 데이터를 저장하는 데 사용됩니다.


    #include 
    #include 
    #include 

    int main() {
        std::ofstream myfile;
        myfile.open ("example.txt");
        myfile << "Writing to this file.\n";
        myfile.close();

        std::string line;
        std::ifstream myfileIn ("example.txt");
        if (myfileIn.is_open())
        {
            while ( getline (myfileIn,line) )
            {
                std::cout << line << '\n';
            }
            myfileIn.close();
        }

        return 0;
    }

이 코드는 "example.txt" 파일에 텍스트를 쓰고, 같은 파일을 열어서 콘솔에 출력하는 작업을 수행합니다. 파일 입출력에 대한 이해는 크고 복잡한 프로그램에서 데이터를 저장하고 로드하는데 필수적입니다.


9. C++에서의 메모리 관리

C++에서는 개발자가 직접 메모리를 할당하고 해제하는 기능을 제공합니다. 이러한 점은 C++의 강력한 기능 중 하나이지만, 동시에 메모리 누수와 같은 문제를 일으킬 수 있는 원인이기도 합니다.

메모리는 new 연산자를 사용해 할당할 수 있으며, delete 연산자를 사용해 해제할 수 있습니다. 이 때 주의할 점은 할당한 메모리는 반드시 개발자가 직접 해제해주어야 합니다.


    int* allocMemory()
    {
        return new int(5);
    }

    int main()
    {
        int* dynamicMemory = allocMemory();
        std::cout << *dynamicMemory << std::endl;

        // 메모리 해제를 잊지말자!
        delete dynamicMemory;

        return 0;
    }

이 코드에서 allocMemory 함수는 동적 메모리를 할당하여 반환합니다. 이 메모리는 main 함수에서 해제됩니다. 만약 이 메모리를 해제하지 않으면, 프로그램이 종료될 때까지 메모리는 계속 점유되어 있게 되어 메모리 누수가 발생하게 됩니다.

이와 같이 C++에서는 메모리 관리를 꼼꼼하게 해야 합니다. 그렇지 않으면 메모리 누수와 같은 문제가 발생할 수 있습니다.


10. C++ 최신 트렌드와 기타 팁

10.1 새로운 표준의 사용

C++은 계속해서 업데이트되고 있습니다. 최신 C++ 표준에서 제공하는 기능을 적극적으로 활용하면 코드를 더욱 효율적이고 안정적으로 작성할 수 있습니다. 예를 들어, C++11부터 추가된 Auto 키워드는 변수의 타입을 자동으로 결정해줍니다.


    int main() {
        auto a = 5;    // int형으로 결정
        auto b = 3.14; // double형으로 결정
        return 0;
    }

10.2 스마트 포인터

C++11부터 도입된 스마트 포인터는 메모리 누수를 효과적으로 방지합니다. 공유 소유권을 가진 `shared_ptr`와 유일한 소유권을 가진 `unique_ptr` 등이 있습니다.


    #include 

    int main() {
        std::shared_ptr ptr(new int(5));

        // 메모리는 자동으로 해제됨
        return 0;
    }

이 코드에서는 shared_ptr을 사용하여 동적 메모리를 할당하고 있습니다. shared_ptr의 소멸자는 포인터가 가리키는 메모리를 자동으로 해제해줍니다. 따라서 개발자는 직접 메모리를 해제할 필요가 없습니다.


Leave a Comment