반응형

상속(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

반응형

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

반응형
  • 대입 연산자
    • 객체의 멤버를 모두 복사해주는 연산자
  • 생성하지 않을경우 컴파일러가 자동으로 제공하는 멤버들
    • 기본 생성자
    • 소멸자
    • 복사 생성자(Shallow Copy)
    • 대입 연산자
    • move 생성자
    • move 대입 연산자
class Point
{
    int x, y;
public:
    Point(int a = 0, int b = 0) : x(a), y(b) {}

    void print() const
    {
        std::cout << x << ", " << y << std::endl;
    }

    Point& operator=(const Point& p)
    {
        x = p.x;
        y = p.y;

        return *this;
    }

};

int main()
{
    Point p1(1, 1);
    Point p2(2, 2);
    Point p3;
    p3 = (p1 = p2);

    (p3 = p1) = p2; // 대입 연산자가 참조 리턴을 하지 않으면 p3에 p2가 대입되지 않음

    p3.print();

}
반응형

반응형

cout의 원리

  • cout은 ostream 타입의 객체
  • <<연산자를 각각의 primitive 타입에 대해서 연산자 오버로딩 한 것
    • cout << 5 : cout.operator<<( int )
    • cout << 3.4 : cout.operator<<( double )

ostream 구현

  • 모든 primitive 타입에 대해서 operator<<() 연산자 함수 제공
  • 연속 출력을 위해서 리턴 값을 자기 자신을 참조 리턴
  • 실제 화면 출력 원리
    • 각 OS가 제공하는 시스템 콜 사용
      • Windows : windows API - WriteFile()
      • Linux : Linux system call - write()
#include <cstdio>
using namespace std;

// std::cout 원리 파악을 위한 구현 예제
namespace std
{
    class ostream
    {
    public:
        ostream& operator<<(int n)
        {
            printf("%d", n);
            return *this;
        }
        ostream& operator<<(double d)
        {
            printf("%f", d);
            return *this;
        }
    };
    ostream cout;
}

int main()
{
    cout << 3; // ostream& operator<<(int n) 호출됨
    cout << 3.4; // ostream& operator<<(double d) 호출됨
    cout << 3 << 4; // 자기 자신을 참조로 리턴하므로 연속 출력 가능
}

유니 코드 출력 팁

  • cout의 정확한 타입은 ostream이 아닌 basic_ostream 템플릿
    • typedef basic_ostream<char> ostream;
    • typedef basic_ostream<wchar_t> wostream;
  • 유니코드 출력
    • ostream cout;
    • wostream wcout;

endl 원리

  • endl은 함수
    • cout << endl;
    • endl(cout);
  • hex, dec, alpha... 등은 모두 함수
    • 입출력 조정자 함수(i/o manipulator)
  • 사용자가 직접 만들 수 있음
    • tab 예제
#include <cstdio>
using namespace std;

namespace std
{
    class ostream
    {
    public:
        ostream& operator<<(int n)
        {
            printf("%d", n);
            return *this;
        }
        ostream& operator<<(double d)
        {
            printf("%f", d);
            return *this;
        }
        ostream& operator<<(char c) // os << '\n'; 지원 위한 연산자
        {
            printf("%c", c);
            return *this;
        }
        ostream& operator<<(ostream& (*f)(ostream&)) // endl 함수 포인터를 담기 위한 연산자
        {
            f(*this); // endl 함수에 자신의 객체 참조 전달
            return *this;
        }
    };
    ostream cout;

    ostream& endl(ostream& os) // 개행
    {
        os << '\n';
        return os;
    }
    
    ostream& tab(ostream& os) // 탭 예제
    {
        os << '\t';
        return os;
    }    
    
}

int main()
{
    cout << 3 << endl; // cout.operator<<( 함수 포인터 )
    cout << 3 << tab << endl; // cout.operator<<( 함수 포인터 )
}

cout 사용자 정의 객체 출력

  • operator<<() 연산자를 일반 함수로 제공하면 가능
class Complex
{
    int re, im;
public:
    Complex(int r = 0, int i = 0) : re(r), im(i) {}

    friend std::ostream& operator<<(std::ostream&, const Complex&);
};

// ostream의 연산자는 상수 함수가 아니므로 접근을 위해 const 객체를 사용하지 않음
std::ostream& operator<<(std::ostream& os, const Complex& c)
{
    os << c.re << "," << c.im; // 사용자 정의 객체의 멤버 데이터를 개별 출력
    return os;
}

int main()
{
    Complex c(1, 1);

    std::cout << c; // cout으로 사용자 정의 객체 출력
}

 

 

반응형

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

C++ 증감 연산자(++, --)  (0) 2019.05.10
C++ 함수 객체(Function Object)  (0) 2019.05.10
C++ 연산자 재정의 - 기본 개념  (0) 2019.05.08
C++ static, const, this  (0) 2019.05.07
C++ 복사 생성자  (0) 2019.05.06

반응형

C++ 상수를 만드는 방법

  • const : 초기값으로 literal뿐 아니라 변수도 사용 가능하다.
  • constexpr : 컴파일 시간 상수, 초기값으로 컴파일 시간에 결정된 값만 사용해야 한다. // C++11
  • 컴파일 타임 상수는 constexpr을 사용하자.
int main()
{
    int n = 10;

    const int c1 = 10;    // OK(컴파일타임 상수)
    const int c2 = n;    // OK(런타임 상수)

    constexpr int c1 = 10;    // OK(컴파일 타임 상수)
    constexpr int c2 = n;    // Error(런타임 상수는 불가)
}

 

C++ 문자열(STL string)

  • string 타입을 사용하자.(STL의 string 클래스)
    • 문자열 처리가 정수형 변수 처럼 직관적으로 사용 할 수 있다.
    • C언어의 const char*로의 변환이 필요하면 .c_str()을 사용한다.
  • C언어에서는 문자열
    • char* 또는 char 배열 사용
    • 복사 및 비교를 위해서는 문자열 전용 함수를 사용
#include <iostream>
#include <string.h>
#include <string>

int main()
{
    // C Style
    char s1[] = "hello";
    char s2[10];

    strcpy(s2, s1);
    if(strcmp(s2, s1) == 0)
    {
    }

    // C++ STL
    std::string s1 = "hello";
    std::string s2;
    
    s2 = s1; // C언어 strcpy(s2, s1) 동일
    if (s1 == s2) // C언어 strcmp(s2, s1) == 0 동일
    {
    }
    
    std::string s3 = s1 + s2;
    std::cout << s3 << std::endl;
}

 

C++ 구조체 바인딩(Structure binding) // C++17

  • 구조체 또는 배열의 각 멤버에서 값을 꺼낼때 사용
  • 타입은 반드시 auto를 사용해야 한다.

struct Point

{

int x = 10;

int y = 20;

};

 

int main()

{

Point p;

 

// 기존 Point 구조체의 멤버값을 복사

int a = p.x;

int b = p.y;

 

// Structure binding을 이용 복사(구조체)

auto [a, b] = p;

 

// Structure binding을 이용 복사(배열도 가능, 배열의 아이템 수가 일치해야 함)

int x[2] = { 1,2 };

auto[a,b] = x;

}

 

 

반응형

+ Recent posts