Eat Study Love

먹고 공부하고 사랑하라

SW 만학도/C++ & Algorithm

Type Casting & Exception Handling + OOP 실습

eatplaylove 2025. 2. 12. 23:31

C++을 이용해서 Type Casting 과 Exception Handling을 해보겠다.

 

Type Casting이란 특정 Variable을 다른 data type으로 변화시키는 것이며 종류로는

 

1. C-style Casting

2. Static cast

3. Dynamic cast

4. Const cast

5. Reinterpret cast

 

이렇게 다섯가지 정도를 알아보자.

Elec* elec = new pikachu();
Fire* char = (Fire*)elec;
// Compile error는 없지만 ERROR

 

static_cast<type> 으로 compile time에 casting을 걸어버려서 깔끔하다.

 

 

Exception Handling은 Try - Catch 구문이다.

일단 try 안쪽에 있는 구문을 실행해보고, 잘 안 되면 catch를 이용해 Error를 Detect한다.

 

It's time to OOP 실습!

Programming의 꽃인 Object Oriented Programming을 실습해보자.

실습 코드는 아래와 같다.

 

exercise_ans.cpp
0.01MB
exercise.cpp
0.00MB

 

이번 실습의 목표는, C++의 Class Inheritance를 이해하는 것이다.

이번 실습을 통해서 animal 이라는 class의 Hierarchy를 구현해보고, virtual function을 이용해 derived class가 base class의 function을 speical하게 Override할 수 있도록 한다.

 

구현하고자 하는 Class의 Overview는 아래와 같다.

가장 상위에 Animal 이라는 Class가 있다.

Static Member로 numAnimals가 있고, Animal 객체의 전체 숫자를 tracking 한다. 이 Attribute는 모든 derived class에 share되며 external code가 이것에 directly 접근할 수 있다. 이것은 constructor로 생성되고, destructor로 삭제되어야 한다.

 

move() 는 pure한 virtual function이다. 이것은, 모든 derived class에서 무조건 implement 되어야 한다. 즉, derived class에 강제성을 부여하는 함수이다.

 

그리고 하위 class에는 Mammal 이라는 class가 있으며 Animal을 상속한다. 즉, Animal class의 모든 property와 function을 상속받는다. move()라는 function을 override하여 "Mammal walks on land!" 라는 text를 출력하게 한다.

그리고 또 다른 class Bird는 역시 Animal Class를 상속받는다. move() 라는 function을 override하여 "Bird flies in the sky!" 라는 문구를 출력한다.

 

그리고 추가로 Bird class에는 fly() method가 있는데, "Bird is flying!" 이라는 text를 출력한다.

 

마지막으로 Penguin class가 있고 Bird class를 상속받는다. 그렇지만 move(), fly() function은 override 하여 Penguin만의 special behavior를 구현한다.

 

move() function은 "Penguin swims but cannot fly."를 출력하며, Penguin은 날지 못하기에, fly() function을 override 할 때 throw a logic_error 를 하여 "Penguin cannot fly!" 문구가 출력되도록 한다. 즉, Penguin object에서 fly()가 실행될 때에는 invalid operation이 throwing an exception을 통해 잘 handling 될 수 있어야 한다.

#include <cassert>
#include <iostream>
#include <stdexcept> // std::out_of_range
#include <string>

/*=============================================== TODO 1 ===============================================
    1. Instruction:
        - Implement the Animal class, which is an abstract class.
        - Introduce a static numAnimals variable inside the class to track the number of Animal objects.
          Becareful that you should initialize numAnimals.
        - The class should have a constructor that increments numAnimals and a destructor
          that decrements it.
        - The `move` function should be a pure virtual function with no parameters and should return void.
          It will be implemented by derived classes to describe how each animal moves.
=======================================================================================================*/
class Animal{
public:
    static int numAnimals;  // 솔직히 static variable 어떻게 생성하는 지 몰랐다.
    virtual void move() const = 0; // virtual , const 위치;;
    Animal(){
        numAnimals += 1;
    }
    virtual ~Animal(){ // Destructor 도 virtual 해준다. -> 그래야 base class A가 삭제될 때 derived class도 쭉 사라진다.
        numAnimals -= 1;
    }
}; // Class 뒤에는 ; 붙쳐준다.

int Animal::numAnimals = 0; // static variable의 경우 이렇게 따로 선언해준다.
// Static variable의 경우 모든 inherited class에 두루 거쳐서 쓰이기 때문에 class외부에 따로 선언

/*=============================================== TODO 2 ===============================================
    1. Instruction:
        - Implement the Mammal class derived from Animal.
        - Override the move function to print "Mammal walks on land!".
    2. Example:
        - ```Mammal mammal; mammal.move();''' should output "Mammal walks on land!".
=======================================================================================================*/
class Mammal : public Animal{ // Inherit은 이렇게 쓴다.
public: // Default는 protected/public이 아니고 private이다. protected는 derived class에선 불러올 수 있다! private는 only 자기 class 안에서만 불러올 수 있는 Attribute.
    void move() const override{
        std::cout << "Mammal walks on land!" << std::endl;
    }
};

/*=============================================== TODO 3 ===============================================
    1. Instruction:
        - Implement the Bird class derived from Animal.
        - Override the move function to print "Bird flies in the sky!".
        - Add a fly function that prints "Bird is flying!".
    2. Example:
        - ```Bird bird; bird.move(); bird.fly();''' should output:
          "Bird flies in the sky!"
          "Bird is flying!"
=======================================================================================================*/
class Bird : public Animal{
public:
    void move() const override{
        std::cout << "Bird flies in the sky!" << std::endl;
    }
    virtual void fly() const{
        std::cout << "Bird is flying!" << std::endl;        
    }
};


/*=============================================== TODO 4 ===============================================
    1. Instruction:
        - Implement the Penguin class derived from Bird.
        - Override the move function to print "Penguin swims but cannot fly."
        - Override the fly function to throw a `logic_error` since penguins cannot fly.
    2. Example:
        - ```Penguin penguin; penguin.move();''' should output:
          "Penguin swims but cannot fly."
        - ```penguin.fly();''' should throw an error with the message "Penguins cannot fly!"
=======================================================================================================*/
class Penguin : public Bird{
public:
    void move() const override{
        std::cout << "Penguin swims but cannot fly." << std::endl;
    }    
    void fly() const override{
        throw std::logic_error("Penguins cannot fly!"); // Well Done
    }
};



///////////////////////// DO NOT MODIFY THIS ///////////////////////// 
void testAnimalMovement(Animal* animal) {
    animal->move();
    
    Bird* bird = dynamic_cast<Bird*>(animal);
    if (bird) {
        try {
            bird->fly();
        } catch (const std::logic_error& e) {
            std::cerr << "Error: " << e.what() << std::endl;
        }
    }
}
///////////////////////// DO NOT MODIFY THIS ///////////////////////// 

int main() {
    /*=============================================== TODO 5 ===============================================
        1. Instruction:
            - Dynamically create 3 objects of type Mammal, Bird, and Penguin class, 
              but each object should be created and accessed using a pointer of type Animal*.
            - After creation, print the number of animals using the static numAnimals.
        2. Example:
            - After creating the objects, the output should be:
              "Number of animals: 3"
    ========================================================================================================*/
    Animal* mammal = new Mammal();
    Animal* bird = new Bird();
    Animal* penguin = new Penguin();
    std::cout << "Number of animals: "<< Animal::numAnimals << std::endl;
    // std::cout << "Number of animals: "<< mammal->numAnimals << std::endl;

    ///////////////////////// DO NOT MODIFY THIS ///////////////////////// 
    std::cout << "Testing Mammal:" << std::endl;
    testAnimalMovement(mammal);  // Expected output: "Mammal walks on land!"
    std::cout << std::endl;

    std::cout << "Testing Bird:" << std::endl;
    testAnimalMovement(bird);    // Expected output:
                                 // "Bird flies in the sky!"
                                 // "Bird is flying!"
    std::cout << std::endl;

    std::cout << "Testing Penguin:" << std::endl;
    testAnimalMovement(penguin); // Expected output:
                                 // "Penguin swims but cannot fly."
                                 // "Error: Penguins cannot fly!"
    std::cout << std::endl;
    ///////////////////////// DO NOT MODIFY THIS /////////////////////////



    /*=============================================== TODO 6 ===============================================
        1. Instruction:
            - Properly delete all objects created earlier.
            - After deletion, print the number of animals again.
        2. Example:
            - After deletion, the output should be:
              "Number of animals: 0"
    ========================================================================================================*/
    delete mammal;
    delete bird;
    delete penguin;

    // std::cout << "Number of animals: "<< mammal->numAnimals << std::endl; 
    // static 멤버 변수는 객체가 아니라 Class에 속하기 때문에 아래와 같이 불러오는 것이 바람직하다.
    std::cout << "Number of animals: "<< Animal::numAnimals << std::endl; 

 

    return 0;
}

 

간단한 코드구현이지만,

 

함수 override와, inherit, static member, destructor/constructor에 대해서 잘 이해할 수 있었던 실습이었다.