티스토리 뷰

190620(3일차) - dynamic_cast, static_cast, const_cast, reinterpret_cast
 
교육을 받으면서 노트필기 했던 내용을 날것 그대로 업로드합니다.

 
#include <iostream>
using namespace std;
 
class AAA {
    int a;
protected:
    int b;
public:
    int c;
};
 
class BBB :public AAA { // private(모든멤버가 private가 되어 상속됨)
    //| protected 상속 (private를 제외한 모든 멤머가 protected가 됨.)
    //기본적으로는 public 상속이됩니다.
public:
    int get_b(void) {
        return b;
    }
};
int main() {
    BBB obj;
    cout << obj.get_b() << endl;
    cout << obj.c << endl;
 
    return 0;
}
 
- 가상함수 : 실제 객체 타입을 찾아서 해당하는 함수를 사용하는 것. 메세지 다형성을 보장하기 위한 것이다. virtual 키워드를 사용한다.
 
#include <iostream>
using namespace std;
 
class AAA {
...
public:
    virtual void print() {
        cout << "Print" << endl;
    }
};
 
class BBB :public AAA { ...
public:
   ...
    void print() {
        cout << "Print2" << endl;
    }
};
int main() {
   
    AAA* a = new BBB();
    a->print(); //print2 호출
 
    return 0;
}
 
- static_case<타입>(대상) : 컴파일 시점에 발생하는 에러를 잡아준며 형변환을 허용하도록 한다. (ex. 부모<->자식)
 
- 가상 소멸자 - 알맞게 메모리 해제를 하기위해 가상 소멸자를 사용한다.
 
class AAA {
    int a;
protected:
    int b;
public:
    int c;
    virtual void print() {
        cout << "Print" << endl;
    }
    virtual ~AAA(); // 가상 소멸자
};
 
- 추상 클래스 : 
virtual void print() = 0;
몸체 자체를 0으로 표현한다. (순수 가상함수)
 

 
#include <iostream>
#include <string>
using namespace std;
 
 
class Engine {
private:
    int hp; // 120~290
public:
    Engine(int hp=120) {
        if (hp < 120)
            hp = 120;
        else if (hp > 290)
            hp = 290;
        this->hp = hp;
    }
    void printHp()const {
        cout << "hp:" << hp << endl;
    }
    void setHp(int value) { hp = value; }
    int getHp() const { return hp; }
};
 
class intercoolerEngine :Engine {
    string cooler; //오일, 물
public:
    intercoolerEngine() {}
    intercoolerEngine(int hp=0, string cooler=""):Engine(hp){
        this->cooler = cooler;
    }
    intercoolerEngine(intercoolerEngine& ie) {
        cooler = ie.cooler;
        setHp(ie.getHp());
    }
    void printHp()const { // 외부에서 조상 접근하기 위해 정의
        Engine::printHp();
    }
    void printHpCooler() const{
        cout << "hp:" << Engine::getHp() << ", cooler:" << cooler << endl;
    }
    int getHp() const{ return Engine::getHp(); } // 외부에서 조상 접근하기 위해 정의
 
    string getCooler() const{ return cooler; }
    //const intercoolerEngine* returnIntercoolerEngine()const { return this; }
};
 
class turboEngine : intercoolerEngine {
    char turborchager; // A,B,C
public:
    /*turboEngine() {}*/
    turboEngine(char chager, int hp = 0, string cooler = ""):intercoolerEngine(hp,cooler){
        turborchager = chager;
    }
    void printChargerHpCooler() const {
        cout << "hp:" << getHp() <<", cooler:" << getCooler() <<", chager:"<<turborchager<< endl;
    }
    void printHp()const {
        intercoolerEngine::printHp(); // 외부에서 조상 접근하기 위해 정의
    }
    void printHpCooler()const {
        intercoolerEngine::printHpCooler();
    }
    
};
 
int main() {
    Engine eng1(150);
    eng1.printHp();
    intercoolerEngine eng2(270,"물");
    eng2.printHpCooler();
 
    intercoolerEngine eng3(eng2); // 복사 생성자로 복사후 출력
    eng3.printHpCooler();
 
    turboEngine eng5('B', 290, "오일");
    eng5.printHp();
    eng5.printHpCooler();
    eng5.printChargerHpCooler();
    return 0;
}
 
- 복사생성자 : 초기화시, 대입시, 함수콜시, 반환시 사용된다.
- 가상상속 : 중복이 되는 클래스는 단 한 번만 상속하겠다. (다중 상속의 문제점을 해결한다.)
- RTTI : type_info, dynamic_cast, 
dynamic_cast<Car*>(&b) : 소괄호를 꺽쇠 형태로 변환. (ex.상속관계에서 사용) , 런타임 시점에 진행된다.
 
(C++ 에서의 형변환 연산)
- dynamic_cast<T>(expr) : 상속관계에서의 안전한 형 변환. T는 객체의 포인터 또는 참조형이어야 한다. 적절하지 않는 경우 컴파일시 에러가 발생한다. 자식(더많은기능) 을 부모(적은기능)에 케스팅할 때 가능하다. 컴파일시간이 아닌 실행시간에 안전성을 검사하도록 컴파일러가 바이너리 코드를 생성한다.
- bad_cast 에러 : 포인터형이아닌 참조형에 잘못된 dynamic_cast연산을 하게되면 NULL값을 참조형에 대입할 수 없기 때문에 bad_cast 에러가 발생한다.
- static_cast : dynamic_cast 보다는 좀더 강력(만능)하다. 안되던 변환이 가능하다. 프로그래머 에게 책임 위임한다. 컴파일 시점에 진행된다. 부모(더적은기능)객체변수에 자식(더많은기능)객체를 할당하고 또 다른 자식객체변수에 그 변수를 자식객체로 형변환하는 경우도 가능하다. (의도적으로 진행하겠다는 것을 내포한다.) (다이나믹에서 안되던 것이 가능하다.) (정말 본인이 책임가능하다면 이 형변환을 사용하자.) (속도는 static_cast가 더 빠르다.)
 소수점 표현을 위해 (double)20/3 등으로 표현하던 코드를 C++에서는 static_cast<double>(20)/3 이라는 코드로 쓸 것을 권장하고 있다. static_cast는 완만히 변환해주는 것 같지만 사실 C 형변환 보다는 엄격한 기준으로 형변환을 진행한다.
- const_cast : const의 성향을 제거하라. 함수사용시 타입이 불일치 할 때 유용하게 사용될 수 있다.
bool func(int *a) {
    return *a == *a;
}
컴파일러가 true로 치환할 수 있는데 컴파일러의 최적화를 막는 키워드 (volatile 성향의 제거도 가능하다.)
- reinterpret_cast : 상관없는 자료형으로의 형 변환. 전혀 상관없어보이는 형변환을 가능하게 한다. (포인터와 관련이 있는 모든 유형의 형변환을 허용한다.)
 
- Ploymorphic 클래스 : 하나 이상의 가상함수를 지니는 클래스이다. 해당 클래스가 하나 이상존재하는 클래스는 dynamic_cast이 가능하다.
 
 

- 내가 작성한 4개의 파일
 
[product.h 파일]
#pragma once
//product.h 파일에는
//product 클래스가 정의되어 있다.
//멤버로 제품명(char *prdName)와 제품금액(int prdPrice)가
//private 멤버로 구성되어있다.
#include <iostream>
#include <cstring>
#pragma warning (disable:4996)
using namespace std;
class product {
private:
    char prdName[20];
    int prdPrice;
public:
    ~product() {
        cout << "product 객체 소멸" << endl;
    }
    void setNamePrice(char* name, int price);
    void printProduct();
};
 
[productcontainer.h 파일]
#pragma once
// productcontainer.h
// productcontainer 클래스가 정의되어 있다.
//product형태의 더블포인터가 있다.
//더블포인터가 가질수 있는 MAX_CNT_PRODUCT 이름의 const 변수가 있다.
//또 더블포인터의 실제 제품갯수의 수인 topindex 가 있다.
//기능에는
//추가(addProduct), 수정(modProduct), 출력(printProduct)
#include "product.h"
class productcontainer {
    product** products;
    const int MAX_CNT_PRODUCT;
    int topindex;//또 더블포인터의 실제 제품갯수의 수인 topindex 가 있다.
public:
    productcontainer(int max) :MAX_CNT_PRODUCT(max) {
        topindex = 0;
        products = new product*[max];
        for (int i = 0; i < max; ++i) {
            products[i] = new product();
        }
    }
    ~productcontainer() {
        cout << "productcontainer 객체 소멸" << endl;
        for (int i = 0; i < MAX_CNT_PRODUCT; ++i) {
            delete products[i];
        }
        delete[] products;
    }
    void addProduct(char* name, int price) {
        products[topindex]->setNamePrice(name, price);
        topindex++;
        cout << "상품입력완료" << endl;
        cout << MAX_CNT_PRODUCT - topindex << "개의 상품이 추가입력 가능합니다." << endl;
 
    }
    void modProduct(int index, char* name, int price) {
        if (index >= topindex || index < 0) {
            cout << "그런 상품 없습니다." << endl;
            return;
        }
        products[index]->setNamePrice(name, price);
    }
    void printProduct() {
        for (int i = 0; i < topindex; ++i) {
            cout << "[" << i << "]번째 상품" << endl;
            products[i]->printProduct();
        }
    }
    void printProduct(int i) {
        if (i >= topindex) {
            cout << "그런 상품 없습니다." << endl;
            return;
        }
        cout << "[" << i << "]번째 상품" << endl;
        products[i]->printProduct();
 
    }
};
 
[product.cpp 파일]
//product.cpp 파일에는
//상품이름, 상품금액을 출력하는 printProduct() 인 멤버함수가 있다.
//상품이름, 상품금액을 추가하는 setPrdInfo() 인 멤버함수가 있다.
#include "product.h"
 
void product::printProduct() {
    //  상품: 공기청정기
        //      금액 : 420000
    cout << "상품 : " << prdName << endl << "금액 : " << prdPrice << endl;
}
 
void product::setNamePrice(char* name, int price) {
    strcpy(prdName, name);
    prdPrice = price;
}
 
[product_main.cpp 파일]
//product_main.cpp에는
#include "productcontainer.h"
 
void print() { //출력만을 기본적으로 하는 전역함수
    cout << "***** 상품 추가 / 수정 / 출력 * ****" << endl;
    cout << "   메뉴 입력                        " << endl;
    cout << "   1)상품추가                       " << endl;
    cout << "   2)상품수정                       " << endl;
    cout << "   3)종합출력                       " << endl;
    cout << "   4)상품출력                       " << endl;
    cout << "   5)종료                             " << endl;
}
 
int main() {
    cout << "상품 입력 개수를 입력하시오 : ";
    int i;
    cin >> i;
    productcontainer p(i);//main함수에는 productcontainer 형 객체를 만들어 이를 관리한다.
    //객체를 생성할때 해당 객체는 내부 product의 maximum 갯수를 만들수있다.
 
    bool loop = true;
    while (loop) {//선택메뉴에 따라 해당 객체 내부의 함수들로 점프한다.
        print();
        cin >> i;
        getchar();
        switch (i) {
        case 5:
            cout << "프로그램을 종료합니다." << endl;
            loop = false;
            break;
        case 1:
            cout << "상품명 : ";
            char name[20];
            cin.getline(name, 20);
            cout << "상품가 : ";
            int price;
            cin >> price;
            p.addProduct(name, price);
            break;
        case 3:
            p.printProduct();
            break;
        case 4:
            cout << "출력 상품 번호 : ";
            cin >> i;
            p.printProduct(i);
            break;
        case 2:
            //cout << "구현 안함";
            cout << "수정 상품 번호 : ";
            cin >> i;
            getchar();
            cout << "새로운 상품명 : ";
            name[20];
            cin.getline(name, 20);
            cout << "새로운 상품가 : ";
            price;
            cin >> price;
            p.modProduct(i, name, price);
            break;
 
        }
    }
}
댓글
댓글쓰기 폼