반응형

추상 클래스(Abstract Class)

  • 순수 가상 함수(Pure Virtual Function)
    • 함수 구현부가 없고 선언부가 "=0"으로 끝나는 가상함수
  • 추상 클래스(Abstract Class)
    • 순수 가상 함수가 한개 이상 있는 클래스
  • 추상 클래스 특징
    • 객체를 만들 수 없음
    • 포인터 타입은 만들 수 있음
  • 추상클래스로 부터 상속 받은 클래스가 순수 가상함수의 구현부를 제공하지 않으면 추상 클래스
  • 추상 클래스의 의도
    • 파생 클래스에게 특정 함수를 반드시 구현을 지시하는 것
    • 인터페이스
#include <iostream>
#include <vector>

// 추상 클래스
class Shape
{
public:
    virtual void Draw() = 0; // 순수 가상함수
};

// 구체 클래스(concerect class)
class Rect : public Shape
{
public:
    virtual void Draw() override
    {

    }
};

int main()
{
    Shape* p; // 추상클래스 포인트는 만들 수 있음
    Rect r; // 추상 클래스를 상속받은 클래스에서 순수 가상함수를 구현하지 않으면 error
}

 

반응형

반응형

도형편집기로 배우는 객체지향 프로그래밍

  • 각 도형을 타입으로 만들면 편함
  • 모든 도형 공통의 기반 클래스가 있으면 각 도형을 묶어서 관리 할 수 있음
  • 모든 도형의 공통의 특징(Draw)는 반드시 기반 클래스(Shape)에도 있어야 함
  • 기반 클래스의 함수 중 파생 클래스가 재정의 하게 되는 모든 함수는 가상함수가 되어야 함

다형성(Polymorphism)

  • 동일한 코드 표현(함수 호출)이 상황에 따라 다르게 동작하는 것
  • OCP(Open Close Principle)
    • 기능 확장에는 열려(Open) 있고 코드 수정에는 닫혀(Close) 있어야 한다는 이론(Principle)
    • 다형성은 OCP를 만족할 수 있는 좋은 코드
#include <iostream>
#include <vector>

// 도형
class Shape
{
public:
    virtual void Draw()
    {
        std::cout << "Shape Draw" << std::endl;
    }
};

// 사각형
class Rect : public Shape
{
public:
    virtual void Draw() override
    {
        std::cout << "Rect Draw" << std::endl;
    }
};

// 원
class Circle : public Shape
{
public:
    virtual void Draw() override
    {
        std::cout << "Circle Draw" << std::endl;
    }
};

// 삼각형
class triangle : public Shape
{
public:
    virtual void Draw() override
    {
        std::cout << "Circle Draw" << std::endl;
    }
};

int main()
{
    std::vector<Shape*> v1; // 도형 저장 버퍼

    while (1)
    {
        int n;
        std::cin >> n;

        if (n == 1) v1.push_back(new Rect); // 사용자 입력이 1일때 사각형 추가
        else if (n == 2) v1.push_back(new Circle); // 사용자 입력이 2일때 원형 추가
        else if (n == 9) // 사용자 입력이 9일때 추가된 도형 전체 출력
        {
            for (int i = 0; i < v1.size(); i++)
                v1[i]->Draw(); // 다형성(Polymorphism) 특징
        }
    }
}
반응형

반응형

오버라이드

  • function override
    • 기반 클래스의 함수를 파생 클래스에서 재정의 할 수 있음
  • 기반 클래스의 포인터로 파생 클래스 객체를 가르킬때(Animal* p = &dog)
    • p->Cry() : C++은 Animal::Cry() 호출, java는 Dog::Cry()  호출
  • virtual function
    • 멤버 함수 호출시, 포인터 타입이 아닌 실제 객체에 따라 함수를 호출
    • 실행 시간에 포인터가 가리키는 메모리를 조사한 후 호출 하는것
// 기본 타입 예제
#include <iostream>
#include <vector>

class Animal
{
public:
    void Cry()
    {
        std::cout << "Animal Cry" << std::endl;
    }
};

class Dog : public Animal
{
public:
    // 함수 오버라이드(override)
    void Cry()
    {
        std::cout << "Dog Cry" << std::endl;
    }
};
int main()
{
    Animal a; a.Cry(); // Animal::Cry() 호출
    Dog d; d.Cry(); // Dog::Cry() 호출

    Animal* p = &d;
    p->Cry(); // Animal::Cry() 호출,  C++에서는 포인터 메모리 타입의 함수를 호출함
}

/////////////////////////////////////////////////////////////

// 가상 함수 변경 예저
#include <iostream>
#include <vector>

class Animal
{
public:
    // 가상 함수
    virtual void Cry()
    {
        std::cout << "Animal Cry" << std::endl;
    }
};

class Dog : public Animal
{
public:
    // 함수 오버라이드(override)
    virtual void Cry()
    {
        std::cout << "Dog Cry" << std::endl;
    }
};
int main()
{
    Animal a; a.Cry(); // Animal::Cry() 호출
    Dog d; d.Cry(); // Dog::Cry() 호출

    Animal* p = &d;
    p->Cry(); // Dog::Cry() 호출, 가상 함수이므로 객체에 따라 함수 호출
}

virtual function

  • 가상 함수 재정의(override)시에는 virtual 키워드는 붙여도 되고 붙이지 않아도 됨
  • 가상 함수 재정의시 실수를 막기 위해서 override 키워드를 사용(C++11)
  • 가상 함수를 선언과 구현으로 분리 할때는 선언부에만 virtual, override을 표기
#include <iostream>
#include <vector>

class Animal
{
public:
    virtual void Cry()
    {
        std::cout << "Animal Cry" << std::endl;
    }
};

class Dog : public Animal
{
public:
    // 함수 오버라이드(override)
    virtual void Cry() override // virtual, override를 제거해도 빌드 되지만 실수 방지용
    {
        std::cout << "Dog Cry" << std::endl;
    }
};
int main()
{
    Animal a; a.Cry();
    Dog d; d.Cry();

    Animal* p = &d;
    p->Cry();
}

 

virtual destructor

  • Upcasting사용시 기반 클래스의 소멸자는 반드시 가상 소멸자여야 함
class Base
{
public:
    Base() { std::cout << "Base 자원 할당" << std::endl; }
    virtual ~Base() { std::cout << "Base 자원 해지" << std::endl;  }
};

class Derived : public Base
{
public:
    Derived()
    {
        std::cout << "Derived 자원 할당" << std::endl;
    }
    virtual ~Derived()
    {
        std::cout << "Derived 자원 해지" << std::endl;
    }
};

int main()
{
    Derived* p = new Derived;
    delete p;
}
반응형

'프로그래밍 언어 > C++' 카테고리의 다른 글

C++ 추상 클래스(Abstract Class)  (0) 2019.05.12
C++ 상속 예제(Polymorphism)  (0) 2019.05.12
C++ 업캐스팅(Up Casting)  (0) 2019.05.12
C++ 상속(Inheritance)  (0) 2019.05.12
C++ STL 정리  (0) 2019.05.12

반응형

Upcasting #1

  • 기반 클래스의 포인터로 파생 클래스를 가리킬 수는 있지만 파생 클래스의 고유한 멤버에 접근은 불가
  • 파생 클래스의 고유 멤버에 접근 하려면 기반 클래스 포인터를 파생 클래스의 포인터 타입으로 캐스팅 해야함
#include <iostream>
#include <string>

class Animal
{
public:
    int age;
    std::string name;
};

class Dog : public Animal
{
public:
    int color;
    int getColor() const { return color; }
};

int main()
{
    Dog dog; // 객체의 포인터 크기, 32bit : 4byte, // 64bit : 64bit

    //int* p = &dog; // error, 서로다른 타입, reinterpret_cast
    Animal* p = &dog; // ok.. 기반 클래스가 -> 파생 클래스를 가르키는 방법
    p->age = 20; // 기반 클래스 멤버
    p->name = "AA"; // 기반 클래스 멤버
    p->color = 1; // 파생 클래스 멤버(error)
    p->getColor(); // 파생 클래스 멤버(error)
    static_cast<Dog*>(p)->color = 10; // 파생 클래스 멤버에 접근을 위해서는 static_cast 필요
}

Upcasting #2

  • 동종(동일한 기반 클래스를 사용하는 클래스)을 처리하는 함수를 만들 수 있음
#include <iostream>
#include <string>

class Animal
{
public:
    int age;
};

class Cat : public Animal {};
class Dog : public Animal {};

void HappyNewYear(Animal* p) // Upcasting이 없으면 Cat*, Dog*... 등의 각 동물별 함수 필요
{
    ++(p->age);
}

int main()
{
    Dog dog;
    HappyNewYear(&dog);

    Cat cat;
    HappyNewYear(&cat);
}
  • 동종을 보관하는 컨테이너를 만들 수 있음
#include <vector>

class Animal
{
public:
    int age;
};

class Cat : public Animal {};
class Dog : public Animal {};

int main()
{
    std::vector<Dog*> v1; // Dog만 보관
    std::vector<Cat*> v2; // Cat만 보관
    std::vector<Animal*> v3; // 모든 동물 보관
}

예제(Composite 패턴)

  • 윈도우 탐색기
    • Folder는 File, Folder를 함께 보관
      • File, Folder는 공통의 기반 클래스가 필요
        • folder : item
        • file : item
      • A, B를 함께 보관하고 싶다면 공통의 기반 클래스가 필요
  • 파워포인트
    • Component
      • Group : Component
      • Shape : Component
        • Rect : Shape
        • Circle : Shape
반응형

'프로그래밍 언어 > C++' 카테고리의 다른 글

C++ 상속 예제(Polymorphism)  (0) 2019.05.12
C++ 오버라이드, 가상함수(Override & Virtual Function)  (0) 2019.05.12
C++ 상속(Inheritance)  (0) 2019.05.12
C++ STL 정리  (0) 2019.05.12
C++ STL 정책(Policy Base)  (0) 2019.05.12

반응형

상속(Inheritance)

  • 정의
    • 클래스 생성시 다른 클래스의 특성을 그대로 이어 받는 방법
  • 상속 문법
    • Student, Professor의 공통 특징을 모아서 Person 클래스를 설계
    • Student, Professor 클래스를 생성시 Person 클래스를 상속 
  • 대부분의 객체지향 언어에서 제공
    • C+++ : class Student : public Person
    • JAVA : class Student extends Person
    • C# : class Stduent : Person
  • 장점
    • 중복 코드 제거
    • 상속을 통해서 기존 클래스에서 새로운 특징 추가
    • 다형성(Polymorphism)을 활용한 객체 지향 디자인
  • UML 표기법
    • 하위(파생)클래스에서 상위(기반) 클래스를 향하도록 화살표를 사용해서 표기
// 사람의 공통 특성을 각 클래스의 멤버로 소유한 예
class Student
{
    int age; // 사람의 공통 특성
    std::string name; // 사람의 공통 특성
    int id; // 학생 번호
};

class Professor
{
    int age; // 사람의 공통 특성
    std::string name; // 사람의 공통 특성
    int major; // 전공
};

int main()
{

}

///////////////////////////////////////////////////////

// 사람의 공통 특성을 Person 클래스로 분리하여 상송 받은 예
// Base(기반), Super
class Person
{
    int age;
    std::string name;
};

// Derived(파생), Sub
class Student : public Person
{
    int id; // 학생 번호
};

class Professor : public Person
{
    int major; // 전공
};

int main()
{
}

상속(Inheritance)의 접근자

  • private:
    • 멤버함수와 friend 함수만 접근 가능
  • protected:
    • 멤버 함수와 friend 함수 접근 가능
    • 파생 클래스의 멤버 함수, 파생 클래스의 friend함수에서 접근 가능
  • public:
    • 멤버 함수와 모든함수에서 접근 가능
class Base
{
private:
    int a;
protected:
    int b;

public:
    int c;
};

class Derived : public Base
{
public:
    void foo()
    {
        a = 10; // 파생 클래스에서 private 접근 error
        b = 10; // 파생 클래스에서 protected 접근 ok
        c = 10; // 파생 클래스에서 public 접근 ok
    }
};

int main()
{
    Base b;
    b.a = 10; // 일반 함수에서 private 접근 error
    b.b = 10; // 일반 함수에서 protected 접근 error
    b.c = 10; // 일반 함수에서 public 접근 ok
}

상속(inheritance) 생성자/소멸자

  • 파생 클래스 객체 생성시 기반 클래스의 생성자/소멸자도 호출됨
  • 생성자/소멸자 호출 순서
    • 기반 클래스 생성자
    • 파생 클래스 생성자
    • 파생 클래스 소멸자
    • 기반 클래스 소멸자
  • 기반 클래스의 생성자는 항상 디폴트 생성자가 호출됨
    • 기반 클래스에 디폴트 생성자가 없을 경우 기본적으로는 파생 클래스의 객체를 생성 할 수 없음
  • 기반 클래스의 디폴트 생성자가 아닌 다른 생성자를 호출하는 방법
    • 파생클래스의 초기화 리스트에서 기반 클래스의 생성자를 명시적으로 호출
// 파생 클래스 객체 생성시 기반클래스의 디폴트 생성자가 호출 예
#include <iostream>

class Base
{
    int data;
public:
    Base() { std::cout << "Base()" << std::endl;  }
    Base(int a) { std::cout << "Base(int)" << std::endl; }
    ~Base() { std::cout << "~Base()" << std::endl; }
};

class Derived : public Base
{
public:
    Derived() { std::cout << "Derived()" << std::endl; }
    Derived(int a) { std::cout << "Derived(int)" << std::endl; }
    ~Derived() { std::cout << "~Derived()" << std::endl; }
};


int main()
{
    Derived d(5);
}
// 파생 클래스의 생성자에의 파라미터 전달 생성시 기반클래스의 Base(int a) 생성자가 호출 예
#include <iostream>

class Base
{
    int data;
public:
    Base() { std::cout << "Base()" << std::endl;  }
    Base(int a) { std::cout << "Base(int)" << std::endl; }
    ~Base() { std::cout << "~Base()" << std::endl; }
};

class Derived : public Base
{
public:
    Derived() {}
    Derived(int a) : Base(a) {} // 기반 클래스의 Base(int a) 생성자 호출 명시
    ~Derived() {}
};


int main()
{
    Derived d(5);
}

상속(inheritance) 생성자/소멸자 호출 원리

  • 파생 클래스의 생성자에서 기반 클래스의 디폴트 생성자를 호출하는 코드를 컴파일러가 제공함
class Base
{
public:
    Base() { std::cout << "Base()" << std::endl;  }
    Base(int a) { std::cout << "Base(int)" << std::endl; }
    ~Base() { std::cout << "~Base()" << std::endl; }
};

class Derived : public Base
{
public:
    Derived() {} // 컴파일러에 의해 내부 코드가  Derived() : Base() {}
    Derived(int a) {} // 컴파일러에 의해 내부 코드가  Derived(int a) : Base() {}
    ~Derived() {} // 컴파일러에 의해 내부 코드가  ~Derived() { ...; 기반 클래스 소멸자 ~Base();}
};

int main()
{
    Derived d(5);
}

Public 생성자

class Animal
{
public:
    Animal() {}
};

class Dog : public Animal
{
public:
};

int main()
{
    // 다음중 에러를 모두 골라 보세요.
    Animal a; // Error 없음, Animal() {} 생성자 사용
    Dog d; // Error 없음, 컴파일러가 기본 생성자 생성, Animal() {} 생성자 호출
}

Private 생성자

class Animal
{
private:
    Animal() {}
};

class Dog : public Animal
{
public:
};

int main()
{
    // 다음중 에러를 모두 골라 보세요.
    Animal a; // Error, Animal() {} 생성자 private이라 접근 불가
    Dog d; // Error, Dog 생성자는 컴파일러가 제공하고, 기반 클래스인 Animal() {} 생성자 호출시 에러
}

Protected 생성자

  • 자신의 객체는 만들수 없지만 파생 클래스의 객체는 만들 수 있음
  • Animal은 추상적(Abstract) 개념이므로 객체가 존재 불가
  • Dog는 구체적(Concrete) 존재이므로 객체가 존재할 수 있음
class Animal
{
protected:
    Animal() {}
};

class Dog : public Animal
{
public:
};

int main()
{
    // 다음중 에러를 모두 골라 보세요.
    Animal a; // Error, Protect 생성자를 일반 함수에서 호출 불가
    Dog d; // OK, 컴파일러가 Dog 디폴트 생성자 제공하고, Animal Protected 생성자 호출됨
}
반응형

'프로그래밍 언어 > C++' 카테고리의 다른 글

C++ 오버라이드, 가상함수(Override & Virtual Function)  (0) 2019.05.12
C++ 업캐스팅(Up Casting)  (0) 2019.05.12
C++ STL 정리  (0) 2019.05.12
C++ STL 정책(Policy Base)  (0) 2019.05.12
C++ STL 알고리즘(Algorithm)  (0) 2019.05.12

반응형

컨테이너(Container)

  • 다양한 알고리즘을 사용하는 자료구조 제공
    • 리스트, 벡터, 트리, 해시

반복자(Iterator)

  • 컨테이너의 내부구조에 상관없이 동일한 방식으로 요소에 접근 제공

알고리즘(Algorithm)

  • 다양한 알고리즘에 처리를 위한 일반함수 제공
    • 선형검색, 이진검색, 정렬, 순열

정책 변경(Policy Base)

  • 알고리즘 및 컨테이너의 정책을 변경
    • 일반 함수, 함수 객체, 람다 표현식 이용

 

 

반응형

'프로그래밍 언어 > C++' 카테고리의 다른 글

C++ 업캐스팅(Up Casting)  (0) 2019.05.12
C++ 상속(Inheritance)  (0) 2019.05.12
C++ STL 정책(Policy Base)  (0) 2019.05.12
C++ STL 알고리즘(Algorithm)  (0) 2019.05.12
C++ STL 반복자(iterator)  (0) 2019.05.12

반응형

알고리즘이 사용하는 정책 변경 방법

  • 일반 함수 사용
  • 함수 객체 사용 - <functional>
  • 람다 표현식 사용(C++11)
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional> // STL 함수 객체

bool cmp(int a, int b) { return a > b; }
int main()
{
    std::vector<int> v = { 1,2,3,4,5,6,7,8,9,10 };

    // 1. 일반 함수 사용.
    //std::sort(v.begin(), v.end(), cmp);

    // 2. 함수 객체
    std::greater<int> g; //>
    std::sort(v.begin(), v.end(), g);

    // 3. 람다 함수 사용, Lambda Expression C++11
    std::sort(v.begin(), v.end(),
        [](int a, int b) { return a > b; }); // [] lambda introducer

    for (auto& n : v)
    {
        std::cout << n << ", ";
    }
}

컨테이너가 사용하는 정책 변경 방법

#include <iostream>
#include <set>
#include <functional> // STL 함수 객체

int main()
{
    std::set<int, std::greater<int>> s; // tree, 컨테이너의 기본값 less<int> 대신 std::greater 사용

    s.insert(10);
    s.insert(30);
    s.insert(20);

    for (auto& n : s)
    {
        std::cout << n << ", ";
    }

}
반응형

'프로그래밍 언어 > C++' 카테고리의 다른 글

C++ 상속(Inheritance)  (0) 2019.05.12
C++ STL 정리  (0) 2019.05.12
C++ STL 알고리즘(Algorithm)  (0) 2019.05.12
C++ STL 반복자(iterator)  (0) 2019.05.12
C++ STL 컨테이너(Container)  (0) 2019.05.11

반응형

STL 알고리즘 특징

  • 멤버 함수가 아닌 일반 함수로 제공
  • <algorithm> 헤더 제공
  • 대부분 함수 인자와 반환 타입으로 반복자를 사용
  • 자료구조에 독립적 동작
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>

int main()
{
    std::list<int> s = { 1,2,3,4,5 };
    std::vector<int> v = { 1,2,3,4,5 };

    auto p1 = std::find(s.begin(), s.end(), 3); list 요소중 3 값 탐색
    auto p2 = std::find(v.begin(), v.end(), 3); vector 요소중 3 값 탐색

    std::cout << *p1 << std::endl;
    std::cout << *p2 << std::endl;
}

find 알고리즘

  • [first, last) 사이의 선형 검색을 수행
  • last는 검색 대상 아님(iterator.end()에 해당하는 마지막 요소 다음 요소)
  • 검색 실패시 0이 아닌 마지막을 요소 반환
#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    std::vector<int> v = { 1,2,3,4,5 };

    // [first, last), 선형 검색, 시작요소는 검색에 포함, 마지막 요소는 검색에 포함되지 않음 의미
    auto p = std::find(v.begin(), v.end(), 3);
    if (p == v.end()) //검색 실패시 v.end() 값 리턴
        std::cout << "검색 실패" << std::endl;

    auto p1 = std::begin(v);
    auto ret = std::find(p1, p1 + 2, 3); // 부분 검색 필요시

    if (ret == p1 + 2)
        std::cout << "실패" << std::endl;

    std::find(ret, std::end(v), 3); // 다음 검색 필요시 두번째 파라미터를 첫째 파라미터로 활용
}

reverse, sort 알고리즘

  • 마찬가지로 iterator의 begin, end 값을 파라미터로 지원
  • 이외 많은 알고리즘이 제공되며 www.cppreference.com 참고
#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    std::vector<int> v = { 1,2,3,4,5,6,7,8,9,10 };

    std::reverse(v.begin(), v.end()); // 집합의 요소 역순 정렬

    for (auto& n : v)
    {
        std::cout << n << ",";
    }

    std::cout << std::endl; // 개행

    std::sort(v.begin(), v.end()); // 집합의 요소 정순 정렬

    for (auto& n : v)
    {
        std::cout << n << ",";
    }
}
반응형

'프로그래밍 언어 > C++' 카테고리의 다른 글

C++ STL 정리  (0) 2019.05.12
C++ STL 정책(Policy Base)  (0) 2019.05.12
C++ STL 반복자(iterator)  (0) 2019.05.12
C++ STL 컨테이너(Container)  (0) 2019.05.11
C++ STL(Standard Template Library)  (0) 2019.05.11

+ Recent posts