ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • C++ Primer CH15. Object-Oriented Programming
    c++ 2024. 1. 21. 16:39

    15.1 OOP: An Overview

    OOP의 주요 아이디어는 데이터 추상화, 상속, 동적 바인딩이다.

    데이터 추상화: 인터페이스와 구현 분리 가능

    상속: 비슷한 타입들간의 관계를 모델링 가능

    동적 바인딩: 비슷한 타입들을 다른점들을 무시하면서 사용 가능

     

    상속

    base class(기본 클래스)

    • virtual 함수를 정의하고 derived class(파생 클래스)가 이를 구현하도록 함
    // base class
    class Quote {
    public:
    	string isbn() const;
    	virtual double net_price(size_t n) const;
    };
    
    // derived class
    class Bulk_quote : public Quote {
    public:
    	double net_price(size_t) const override;
    };
    

    override

    • base class의 virtual function을 구현할 때 붙임.

    동적 바인딩(dynamic binding)

    동적 바인딩이란? 런타임시점때 호출될 메서드가 결정되는 것

    가상함수가 base class(기본 클래스)의 참조를 통해 호출될 때 일어난다.

    double print_total(ostream &os, const Quote &item, size_t n) {
    	double ret = item.net_price(n);
    	os << "ISBN: " << item.isbn();
    		 << " # sold: " << n << " total due: " << ret << endl;
    	return ret;
    }
    
    • 위 코드에서 어떤 부분이 동적 바인딩이 일어나는가?
    • -> 컴파일시점에 결정되지 않고 런타임시점에 결정된다.
    • -> 함수의 인자 중 const Quote &item에서 Quote를 넣을 지 Bulk_quote를 넣을 지에 따라 사용될net_price() 메서드의 구현체가 달라진다.

    15.2.1 Defining a Base Class

    class Quote {
    public:
    	Quote() = default;
    	Quote(string &book, double sales_price): bookNo(book), price(sales_price) {}
    	string isbn() const { return bookNo; }
    	
    	virtual double net_price(size_t n) const { return n * price; }
    	virtual ~Quote() = default;
    private:
    	string bookNo;
    protected:
    	double price = 0.0;
    };
    

    virtual이 붙지 않은 함수는 컴파일 시점에 해석된다.

    • private과 protected 차이?
    • -> protected: 해당 클래스 내부, 파생클래스 내부에서만 직접접근 가능
    • -> private: 해당 클래스 내부에서만 직접접근 가능.

    파생 클래스에서 기본 클래스의 생산자(constructor) 사용하기

    class Bulk_quote : public Quote { // Bulk_quote inherits from Quote Bulk_quote() = default;
    	Bulk_quote(const std::string& book, double price, std::size_t qty, double disc) :
    		Quote(book, price), min_qty(price), discount(disc) {}
    	// overrides the base version in order to implement the bulk purchase discount policy
    	double net_price(std::size_t) const override;
    private:
    	std::size_t min_qty = 0; // minimum purchase for the discount to apply
    	double discount = 0.0; // fractional discount to apply
    };
    

     

    Inheritance and static Members

    한 클래스에 static 멤버가 있고 파생클래스가 생성될 때 저 static 멤버는 새로 생성되지 않는다.

    class Base {
    public:
    	static void statemem();
    };
    class Derived : public Base {
    	void f(const Derived&);
    };
    
    void Derived::f(const Derived &derived_obj) {
    	// 4개 다 가능
    	Base::statemem();
    	Derived::statemem();
    	derived_obj.statemem();
    	statemem();
    }
    

     

    interitance chain

    class Base {}
    class D1 : public Base {}
    class D2 : public D1 {}
    
    • direct base, indirect base 구분
    • -> D2에게 Base: indirect base
    • -> D1에게 Base: direct base

    상속 막기

    클래스 선언시 final 붙이면 된다.

    class NoDerived final {};
    

    15.2.3 Conversions and Inheritance

    원래 참조나 포인터는 같은 타입일 때만 바인딩 가능했는데, class인 경우 파생클래스 타입이 기본클래스 타입을 바인딩할 수 있다는 예외가 있다.

     

    정적 타입과 동적 타입

    double ret = item.net_price(n);
    

    여기서 item의 정적 타입은 Quote&

    실제 바인딩되는 타입, 즉 동적타입은 실행되고 나서 알 수 있음.

     

    Derived ← Base 방향의 conversion는 없다(에러).

     

    Derived로 Base 만드는 법

    Bulk_quote bulk;
    1. Quote item(bulk);
    2. Quote item = bulk;
    

    Bulk_quote 중 오직 Quote에 해당하는 부분만 복사되고 나머지 파생된 부분은 무시된다.

    15.3 Virtual Functions

    순수 가상함수일 경우에는 파생 클래스에서 무조건 정의해야 하고, 기본 클래스에서 이미 정의가 되어 있다면 파생 클래스에서 정의하지 않아도 컴파일은 되지만 정의 하는게 좋다.

    • 정적,동적타입인지 판단하는 법?
    • 해당 클래스의 구현 타입이 바뀔 수 있으면 동적, 없으면 정적 + 가상 변수에 접근하고 포인터나 참조로 선언된 변수라면 동적 타입
    Quote base = derived; 
    base.net_price(20); // 타입은 무조건 Quote임
    

     

    파생 클래스에서 virtual 함수를 구현할 땐 인자 타입, 개수, 반환 타입이 모두 같아야 한다.

    • 반환 타입의 예외
    • -> 기본 클래스의 virtual 함수의 반환 타입이 자기 자신의 참조 혹은 포인터인 경우,
    • -> 파생 클래스는 상속관계에 있으므로 자신의 참조 혹은 포인터 반환할 수 있다.

    final과 override

    override

    • 가상함수를 구현하고 있다는 표시를 하는 역할
    • 의도 확인, 오류 방지(컴파일러가 체크), 가독성
    strubt B {
    	virtual void f1(int) const;
    	virtual void f2();
    	void f3();
    };
    
    struct D1 : B {
    	void f1(int) const override; // OK
    	void f2(int) override; // B has no f2(int) virtual function
    	void f3() override; // B's f3 is not virtual
    	void f4() override; // there's not virtual f4
    

     

    final

    final 붙은 함수는 override할 수 없다.

    struct D2 : B {
    	void f1(int) const final; // 다음에 D2의 파생클래스는 f1를 override할 수 없다.
    };
    struct D3 : D2 {
    	void f2(); // B에서 virtual이라서 override 가능
    	void f1(int) const; // D2에서 final이라서 override 불가
    };
    

     

    동적 바인딩 막는 법

    double undiscounted = baseP->Quote::net_price(42);
    // baseP는 인자로 들어온 참조변수. Quote에 접근해서 net_price 호출
    // 실행타입이 무조건 Quote이므로 컴파일시점에 타입 정해짐.
    
    • 왜 막는 경우가 필요하나?
    • -> 파생클래스에서 기본 클래스에 있는 공통 작업을 수행해야 할 때 사용

    scope operator 안쓰고 호출시 무한재귀호출 발생 위험 존재

    class Derived : public Base {
    public:
        void myFunction() const override {
            // 범위 연산자를 사용하지 않고 기본 클래스의 버전을 호출하려는 의도
            myFunction();  // 잘못된 호출: 무한 재귀가 발생할 수 있음
            std::cout << "Derived::myFunction\\n";
        }
    

    15.4 Abstract Base Classes

    추상 클래스: 순수 가상 함수를 포함하고 있는 클래스

    • 파생 클래스가 override할 인터페이스를 정의하는 역할

    순수 가상함수

    • virtual 키워드, = 0 이 붙음
    // class to hold the discount rate and quantity
    // derived classes will implement pricing strategies using these data
    class Disc_quote : public Quote {
    public:
    	Disc_quote() = default;
    	Disc_quote(const std::string& book, double price,
    		std::size_t qty, double disc): Quote(book, price), quantity(qty), discount(disc) { }
    	double net_price(std::size_t) const = 0; // 순수가상함수 구현 안해서 Disc_quote도 추상클래스다.
    protected:
    	std::size_t quantity = 0; // purchase size for the discount to apply
    	double discount = 0.0; // fractional discount to apply
    };
    

    파생 클래스에서 추상 클래스 함수 구현 안하고 순수 가상함수로 구현했다면 이 파생클래스 역시 추상 클래스다.

     

    추상 클래스는 단독으로 만들어질 수 없다.

    // 둘다 기본 생성자가 호출됨
    Disc_quote discounted; // error. Disc_quote가 추상 클래스다.
    Bulk_quote bulk; // OK. pure virtual function 없어서 추상 클래스 아님.
    
    // the discount kicks in when a specified number of copies of the same book are sold
    // the discount is expressed as a fraction to use to reduce the normal price
    class Bulk_quote : public Disc_quote {
    public:
    	Bulk_quote() = default;
    	Bulk_quote(const std::string& book, double price,
    		std::size_t qty, double disc): Disc_quote(book, price, qty, disc) { }
    	// overrides the base version to implement the bulk purchase discount policy
    	double net_price(std::size_t) const override;
    };
    
    • constructor 호출과정
    • -> Bulk_quote → Disc_quote → Quote(완료) → Disc_quote(완료) → Bulk_quote(완료)

    15.5 Access Control and Inheritance

    접근 제한 거는 키워드들

    • public, private, protected

    public: 해당 클래스 내부 외부에서 다 접근 가능

    protected: 해당 클래스 내부 + 파생 클래스 내부에서 접근 가능

    private: 해당 클래스 내부에서만 접근 가능

     

    멤버에 접근 제한 걸기

    class Base {
    public:
    	void pub_mem();
    protected:
    	int prot_mem();
    private:
    	char priv_mem;
    };	
    

     

    상속받을 때 접근 제한 걸기

    direct base class(여기선 Base)에 접근할 땐 derivation access(private Base에서 private) 무시됨.

    struct Pub_Derv : public Base {
    	int f() { return prot_mem; } // ok
    	char g() { return priv_mem; } // error, priv_mem이 private이기 때문에.
    }
    
    struct Priv_Derv : private Base {
    	int f1() const { return prot_mem; } // ok. private으로 상속받았지만 멤버변수 접근에 영향 안줌
    
    

     

    derivation access의 목적: 파생 클래스 사용자가 접근할 때 제한 두기 위함

    Pub_derv d1;
    Priv_Derv d2;
    d1.pub_mem(); // ok, Pub_derv는 public Base 상속했기 때문
    d2.pub_mem(); // error, Priv_Derv는 private Base 상속했기 때문
    

     

    15.6 Class Scope under Inheritance

    15.7 Constructors and Copy Control

    Virtual Destructor: 객체 파괴할 때 사용됨


    15.8 Containers and Inheritance

    15.9 Text Queries Revisited

    'c++' 카테고리의 다른 글

    C++ Study. final, override  (1) 2024.01.21
    C++ 스터디. standard template library  (1) 2024.01.21
    C++ Primer CH13. Copy Control  (0) 2024.01.21
    C++ Primer CH12. Dynamic Memory  (0) 2024.01.21
    C++ Primer CH11. Associative Containers  (1) 2024.01.21
Designed by Tistory.