본문 바로가기
  • 쓸쓸한 개발자의 공부방

C++46

[C++] 디자인 패턴 : 변하는 것을 분리하는 방법 2가지 [C++] 디자인 패턴 : 변하는 것을 분리하는 방법 2가지 클래스를 정의하고 상속 받아서 사용하는 경우 재사용성을 고려하는 디자인 패턴에 대해 알아야 한다. 변하지 않는 코드(전체 흐름) 안에 있는 변해야 하는 부분(정책)은 분리 하는 것이 좋다. 1) template method : 변하는 것을 가상함수로 (상속 기반) 변해야 하는 부분 (아래에서 validate 함수)을 별도의 가상 함수로 분리한다. 변하는 것 (validate)을 가상 함수로 분리할 때의 장점 - validation 정책을 변경하고 싶다면 Edit의 파생 클래스를 만들어서 validate() 가상 함수를 재정의하면 된다. template method 장단점 상속 기반은 유연성이 떨어지는 편, 재사용이 크게 필요없는 경우 명확한 편.. 2022. 1. 30.
[C++] 디자인패턴 : uscasting [C++] 디자인패턴 : uscasting upcasting 기반 클래스 타입의 포인터(참조)로 파생 클래스 객체를 가리킬 수 있다. class Animal { int age; }; class Dog : public Animal { int color; }; int main() { Dog d; Dog* p1 = &d; // ok. double* p2 = &d; // error. Animal* p3 = &d; // ok. } Dog 형태의 d 는 age, color를 가지고 있다. Animal p3에를 메모리를 찾아가면 age 존재하기 때문에 문제가 없다. 폴더와 파일의 관계를 생각해볼 수 있다. 폴더는 폴더 안에 폴더와 파일을 가질 수 있다. 그래서 폴더와 파일을 동시에 가질 수 있는 기반 객체 Item을.. 2022. 1. 28.
[C++] 디자인패턴 : protected constructor C++ 디자인 패턴 : protected constructor (protected생성자) 생성자의 정확한 호출 순서를 이해해야 한다. 1. Dog의 생성자가 먼저 호출된다. (Dog d; 에 의해 호출됨) 2. Dog의 생성자 안에서 기반 클래스인 Animal의 생성자를 호출한다. class Animal { protected: Animal() {} }; class Dog : public Animal { public: Dog() {} // Dog() : Animal() {} }; int main() { Animal a; // error Dog d; // ok. } 생성자를 protected에 만드는 이유? - 자기 자신(Animal)을 만들 수는 없다. - 하지만 파생 클래스(Dog)의 객체는 만들 수 있.. 2022. 1. 27.
[C++] Design Patterns (디자인 패턴) - GoF [C++] Design patterns (디자인 패턴) - GoF 총 23가지의 패턴을 소개하고 있습니다. 개발자들끼리 대화하고 업무의 효율을 높여주는 디자인 패턴은 개발자에게 필수적입니다. 위의 왼쪽 책은 1995년 발간된 디자인 패턴 책입니다. 기존의 존재하는 코딩 방식에 이름을 부여해 책으로 펼쳐냈습니다. 위의 오른쪽 책은 한글 개정판으로 2015년 출판된 책입니다. 부제목은 "재사용성을 지닌 객체지향 소프트웨어의 핵심 요소" (Elements of Reusable Object-Oriented Software) 라고 되어 있네요. 다른 국적의 저자 4명이 함께 책을 썼습니다. 에릭 감마, 리처드 헬름, 랄프 존슨, 존 블리시디스 그래서 4명의 갱이라고 해서 GoF (Gang of Four) 의 디자.. 2022. 1. 26.
[C++] exception (예외처리) exception c언어에서 함수가 실패하면 함수의 반환 값(retrun value)을 사용해서 실패했음을 알린다. - 반환 값과 실패하는 것이 명확히 분리되지 않는 단점이 있다. - 정상적인 실행흐름과 오류처리의 코드가 분리되어 있지 않는 단점이 있다. - 중요하고 심각한 오류라도 오류를 무시할 수 있는 단점이 있다. (오동작에 대한 버그 처리에 어려움) 객체지향 언어들이 사용하는 오류 처리가 바로 exception 처리 - 함수가 실패하면 throw 키워드를 사용해서 예외를 던진다. - 던져진 예외를 처리하지 않으면 프로그램은 종료된다. catch문은 여러 개를 만들 수 있다. catch( ... )은 모든 종류의 예외를 잡을 수 있다. 해당 구문은 맨 나중에만 넣을 수 있다. #include int.. 2022. 1. 10.
[C++] cout, endl 원리, operator<< 재정의 cout 원리 cout 은 ostream 타입의 객체이다. 모든 primitive 타입에 대해서 operator 2022. 1. 2.
[C++] 연산자 재정의 (operator overloading) 연산자 재정의 (operator overloading) 연산자 재정의란 +, -, * 의 연산자를 함수로 만들 수 있다. operator+, operator-, operator* #include class Point { int x; int y; public: Point( int a = 0, int b = 0) : x(a), y(b) {} }; int main() { int n = 1 + 2; Point p1(1,1); Point p2(2,2); Point p3 = p1 + p2; // operator+(p1, p2) // operator+(Point, Point) // p1.operator+(p2) => operator+(Point) ¸âšöÇÔźö } a+b를 컴파일러가 해석하는 방법 a,b 모두 pr.. 2022. 1. 1.
[C++] 다중 상속 (multiple inheritance) 다중 상속 (multiple inheritance) 다중 상속은 클래스가 2개 이상의 기반 클래스로 부터 상속 되는 것이다. - C++, Lisp, Curl 다중 상속 지원 - Java, C# 다중 상속 미지원 문제점 : 서로 다른 기반 클래스에 동일 이름의 멤버가 있을 때 이름 충돌, 다이아몬드 형태의 상속 class InputFile { public: void read() {} void open() {} }; class OutputFile { public: void write(){} void open() {} }; class IOFile : public InputFile, public OutputFile // 다중 상속 지원 { }; int main() { IOFile file; file.open().. 2021. 12. 31.
[C++] 상속과 RTTI 상속과 RTTI 함수가 인자로 기반 클래스의 포인터를 받으면 - 기반 클래스 뿐 아니라 모든 파생 클래스를 전달 받을 수 있다. 기반 클래스 포인터로 파생 클래스의 고유 멤버에 접근 할 수 없다. - 파생클래스의 고유 멤버에 접근하려면 파생 클래스 타입으로 캐스팅 (다운 캐스팅, downcasting) 해야 한다. #include #include class Animal {}; class Dog : public Animal { public: int color; }; void foo(Animal* p) { // p가 Dog 이라면 p->color = 10; // error } int main() { Animal a; foo(&a); Dog d; foo(&d); } 아래와 같이 p는 Animal 클래스 형태로.. 2021. 12. 30.
[C++] RTTI (Run Time Type Information) RTTI(Run Time Type Information) 실행시간에 타입의 정보를 얻을 때 사용하는 기술 헤더 포함하고 typeid 연산자를 사용하면 된다. 타입의 정보를 담은 type_info 객체를 얻을 수 있다. type_info 객체의 멤버 함수 name()을 사용해 출력 가능하다. #include #include int main() { int n1 = 10; auto n2 = n1; // n2의 타입은 int ? const std::type_info& t1 = typeid(n2); std::cout 2021. 12. 29.
[C++] 추상 클래스 (abstract class), 인터페이스(interface) 순수 가상 함수 (pure virtual function) - 함수의 구현부가 없고, 선언부가 =0 으로 끝나는 가상함수 추상 클래스 (abstract class) - 순수 가상 함수가 한 개 이상 있는 클래스 - 객체를 생성할 수 없다. - 포인터 변수는 만들 수 있다. #include using namespace std; class Shape { public: virtual void Draw() = 0; }; int main() { Shape s; // error Shape* p; } 출력 : 추상 클래스의 객체를 생성할 수 없기 때문에 에러가 발생한다. main.cpp:21:11: error: cannot declare variable ‘s’ to be of abstract type ‘Shape’ .. 2021. 12. 28.
[C++] virtual function (가상 함수), function override(오버라이드) 주의! 함수 오버라이드가 c++에서 가능하지만 권장하지 않는 코딩이다. 그저 참조용으로만 알아둘 것. 함수 재정의가 필요한 경우에는 무조건 virtual 을 사용해야 한다. 함수 오버라이드 (function override) - 기반 클래스가 가진 함수를 파생 클래스가 다시 만드는 것 - 주의! 오바라이딩과 오버로딩(overloading)은 다른 용어 #include class Shape { public: void Draw() { std::cout 2021. 8. 28.
[C++] upcasting (업캐스팅) upcasting (업캐스팅) - 기반 클래스 타입의 포인터로 파생 클래스를 가리킬 수 있다. - 기반 클래스 타입의 참조로 파생 클래스를 가리킬 수 있다. class Shape { public: int color; }; class Rect : public Shape { public: int x, y, w, h; }; int main() { Rect rect; Rect* p1 = ▭ // ok int* p2 = ▭ // error. Shape* p3 = ▭ // ok Shape& r = rect; // ok. } main.cpp:18:18: error: cannot convert ‘Rect*’ to ‘int*’ in initialization Shape* p3 = ▭ .. 2021. 8. 27.
[C++] 상속과 생성자 (파생 클래스 구현 방법 및 호출 순서) 상속과 생성자 파생 클래스의 객체 생성시 생성자와 소멸자 호출 순서 1. 기반(base) 클래스 생성자 2. 파생(Derived) 클래스 생성자 3. 파생(Derived) 클래스 소멸자 4. 기반(base) 클래스 소멸자 #include using namespace std; class Base { int data; public: Base() { cout 2021. 8. 26.
[C++] 상속 (Inheritance), protected 상속(INHERITANCE) - 한 클래스가 다른 클래스에서 정의된 속성들 (데이타, 함수) 를 이어 받아서 사용하는 것! - 이미 정의된 클래스를 기반으로 새로운 클래스를 설계 - 소프트웨어 재사용성을 지원 장점 - 코드 중복을 막는다 - 상속을 통해서 기존 클래스에 새로운 특징을 추가한 새로운 타입의 설계 - 다형성을 활용한 객체지향 디자인 기법 상속의 기본 개념 교수님과 학생 클래스가 아래와 같이 있다. 두 클래스는 이름과 나이의 공통 속성이 있다. #include #include class Professor { std::string name; int age; int major; }; class Student { std::string name; int age; int id; }; int main().. 2021. 8. 25.
[C++] this 포인터 this 포인터 - 멤버 함수 안에서 사용가능한 키워드 - 자신을 호출한 객체의 주소를 담고 있다. 객체를 여러 개 생성 할 때 멤버 데이터는 객체당 한 개씩 메모리에 놓이게 된다. 멤버 함수는 객체의 개수에 상관없이 코드 메모리에 한 개만 있다. #include class Point { int x = 0; int y = 0; public: void set(int a, int b) { std::cout x = x; this->y = y; return *this; } }; int main() { Point p1; //p1.set(10,20)->set(30,40)->set(40,50); // 포인터를 반환하면 "->" 사용가능 p1.set(10,20).set(30,40).set(40,50); // cout의.. 2021. 8. 24.
[C++] 상수 멤버 함수 const 상수 멤버 함수 const 함수 선언 및 구현시 함수 괄호 ( ) 뒤에 const가 붙는 함수 void print() const - 상수 멤버 함수 안에서는 모든 멤버를 상수 취급한다. - 멤버 데이터의 값을 읽을 수는 있지만 변경할 수는 없다. - 코드 작성시 안정성 - 상수 객체는 상수 멤버 함수만 호출할 수 있다. #include class Point { int x, y; public: Point(int a = 0, int b = 0) : x(a), y(b) {} void set( int a, int b ) { x = a; y = b; } void print() const // 상수 멤버 함수 { x = 10; // error : 상수 멤버 함수 안에서 모든 멤버를 상수 취급하기 때문에 변경시 에러.. 2021. 8. 23.
[C++] static member (정적 멤버), static 변수, static 함수 static 변수는 실무에서 사용에 매우 제한을 두는 코딩이다. 메모리가 할당되어 계속 자리를 차지 하고 있기 때문이다. 사용 방법을 정확히 파악해 꼭 필요한 경우에만 static 변수를 선언해 사용하자. static member 전역 변수 기본 접근 : 자동차의 총 개수를 파악하기 위한 전역 변수를 아래와 같이 사용이 가능하다. #include int cnt = 0; // 전역 변수 // 자동차의 총 개수를 파악하기 위해 cnt 변수 선언 class Car { int speed; int color; public: //int cnt = 0; // member 로 만들면 각 클래스 마다 각자 정보를 갖고 있음. Car() {++cnt;} ~Car() {--cnt;} }; int main() { Car c1.. 2021. 8. 22.
[C++] 복사 생성자 (copy constructor), 얕은 복사 (Shallow Copy), 깊은 복사 (deep copy) 눈에 잘 드러나지 않는 자동 생성되는 코드를 이해하는 부분이 항상 까다롭다. 그 중 하나가 복사 생성자다. 대부분 자동으로 생성되는 복사 생성자를 사용하게 되고 큰 문제는 없다. (좀더 인텔리전트한 개발자가 되기 위해서) 몇몇 부분에서 성능 향상에 도움이 되는 복사 생성자 정의하는 포인트가 있다. 알아두면 정말 좋은 내용이다. copy constructor ( 복사 생성자 ) - 자신과 동일한 타입 한 개를 인자로 가지는 생성자 - 사용자가 복사 생성자를 만들지 않으면 컴파일러가 자동으로 제공한다. - 디폴트 복사 생성자다 (default copy constructor) - 모든 멤버를 복사 한다. #include class Point { public: int x; int y; Point() : x(0).. 2021. 8. 21.
[C++] Explicit 생성자 Explicit 생성자 explicit a. 명백한, 뚜렷한(clear), 명시적인 - 직접 초기화 (direct initialization) : OFile fi("a.txt");와 같이 '=' 없이 초기화 하는 것 - 복사 초기화 (copy initialization) : OFile f2 = "a.txt"; 와 같이 '=' 사용해서 초기화 하는 것 함수 인자 전달시 복사 초기화를 사용한다. foo("hello")를 보낸다는 것은 hello 이름으로 File이 error 없이 생성이 된다. 특정 클래스 설계시 복사 초기화를 사용하지 못하게 하는 것이 좋을 때가 있다. #include class OFile { FILE* file; public: OFile(const char* filename) { file.. 2021. 8. 20.