c++의 역사
비아르네 스트로우스투루프가 창시.
처음에는 C언어의 확장판 개념으로 사용하게 되었다. 절차지향이던 C언어에 클래스/상속/... 이런 것들을 넣어서 언어를 확장했다.
1982년도에 C++로 이름이 바뀌었다. (이전에는 C with classes)
1985년도에 C++가 어떤 언어인지 배포되고, implementation(컴파일러)도 생겼다.
C++ 디자인은 객체 지향 프로그래밍이라는 개념이 있다.
C언어의 확장판이 C++인가?
C언어의 Syntax가 매우 비슷하다. 어떻게 실행되는지도 유사하다.(Similar Sementics)
메모리 관리도 매우 비슷하다.
현재는 C의 확장이라고 보기에는 어렵다. 왜냐하면, C의 컴파일러로 컴파일 실행 했을 시 C++ 코드의 실행이 다를 수 있다.
컴파일러만 달라졌을 뿐인데도 결과가 달라진다.
언어가 실제로 어떻게 동작하는지를 보려면 레퍼런스 메뉴얼을 봐야한다.(언어의 스펙)
C언어가 어떻게 동작하는지/C++ 언어가 어떻게 동작하는지 책이 있다.
#include <stdio.h>
int main() {
printf("Size : %d", sizeof('a'));
return 0;
}
C는 int로 보고/ C++은 char로 본다.
아스키 코드로 보는 C는 정수로 본다.
OOP concepts / 한글 보단 영어로 익혀두는 것이 좋다. -매년 시험문제.
- Class and Object
- Abstraction
- Encapsulation
- Inheritance
- Polymorphism
클래스란 무엇인가.
하나의 분류/ 하나의 틀 이라고 볼 수 있다. 간단하게 어떠한 분류라고 생각하자.(어떤 특성을 공유하는 분류)
클래스는 두 가지로 분류되어 있는데 특성(Properties)와 행동(Behavior)이 있다. Attributes / Methods
객체는 instance of class이다. 객체는 상태와 행동을 가지고 있다. (행동은 클래스의 행동을 그대로 가져갔다고 보면 된다.)
특성이 아닌 상태인 이유는 특성은 이름이 있다. 색상이 있다. 연도가 있다. 이런 것인 반면 상태는 이름이 뭐 다. 색상이 이렇다. 연도는 몇 년도이다. 라는 특성의 값을 갖고 있다.
객체에 이러한 행동을 시켰을 때 상태가 변화할 수 있다.
클래스와 객체.
클래스는 분류/ 객체는 이 분류에 속하는 것.
생성자가 먼저 걸리면 이니셜라이제이션 리스트를 훑고 생성자 몸체를 실행한다. 이니셜라이제이션 리스트는 ,(콤마)로 구분한다.
자바와는 다르게 객체를 생성할 때, new를 안 사용한다. Car my_car("BBabang", 2020, color.Red);
#include <stdio.h>
using namespace std;
class Car {
public:
Car(string name, int purchase_year, Color color) : name_(name),
purchase_year_(purchase_year), color_(color) {} // 이니셜라이제이션 리스트. 초기화.
//
private:
string name_; int purchase_year_; Color color_;
}; // 끝에 세미콜론 빼먹지 않기.
int main() {
Car my_car("BBabang", 2020, color.Red);
return 0;
}
추상화[Abstraction]는 디테일이 없어도 만들 수 있는 것이다. 어떻게 메소드가 구현되어 있는지 정확히 몰라도 사용할 수 있다.
implementation이 없어도 어떻게 작용하는지만 알고 있어도 사용할 수 있다. 어떤 방식으로 작동하는 지는 몰라도 가져다가 쓰는데에는 문제 없다. 어떤 기능이 있는지만 알아도 사용.
자바에서는 함수 몸체를 만드는 것을 구현, 정의라고 한다. C++에서는 정의와 선언이 명확하게 구분한다. 멤버 펑션을 호출할 때는 자바와 동일하게 객체.메소드() 하면 된다. EX) my_car.Opendoor();
캡슐화[Encapsulation]는 특정한 것을 캡슐로 따놓겠다. 자동차라는 객체가 상태를 갖고 있다고 하자. 2개의 상태 : 현재 속도와 문이 열려있는지.
interfaces를 통해서만 상태에 접근할 수 있도록 한다. 내부 로직을 캡슐로 보호한다. (실제 자동차의 현재 속도를 알기 위해서는 자동차의 계기판을 확인하듯이 인터페이스는 계기판이라고 생각하면 된다.)
캡슐화는 private으로 함부로 접근해서 변경할 수 없도록 한다. 멤버 필드를 private으로 넣어놨다면 public을 통하여 바꾸어야 한다.
상속[Inheritance]은 세부 분류를 만드는 것이라고 생각하자. 클래스에 대한 세부 분류를 더 만든다. 기존 분류가 갖고 있던 것에 추가적인 특성이나 행동을 부여하는 것이다. 큰 분류를 superclass라고 하고, 그 아래 작은 분류를 subclass/ parent class-child class/ base class-derived class라고도 한다. 이런 쌍을 잘 알고 있어야 한다.
상속을 한다는 것은 부모의 특성을 자식이 그대로 물려받고 세부 분류이기 때문에 추가적인 행동 및 특성을 부여받게 된다. 부모 클래스의 확장이라고 생각.
C++에서 상속은 class Bus : public Car { ... } 자바에서는 extends를 사용했던 것과 달리 : 을 사용한다. 33분
다형성[Polymorphism]은 하나를 사용했는데 여러가지 형태를 띌 수 있다는 것이다. 상속이라는 것도 폴리모피즘을 이용하는 방법이다. 자동차를 사용했지만 실제로는 버스일 수도 있다. 크게 두가지로 나누어서 설명한다. 스태틱/다이나믹 폴리모피즘. 스태틱은 컴파일 이전에서 컴파일 시점까지. 다이나믹은 실행 시점일 때 runtime일 때.
컴퓨터는 모호성을 받아들이기 어려움을 겪는다. 스태틱은 컴파일 시 A를 B로 사용하게 될 때 B로 바꾸어버리는 것. 다이나믹은 실행되다가 A를 만났을 때 B이다. 그럼 B로 바꾸고, 다시 A를 만났을 때 C이다. 그러면 C로 바꾼다.
스태틱은 Method Overloading / Method Overriding
다이나믹은 Virtual function call이다.
오버로딩 똑같은 함수를 여러 개 정의.
void f(int x) ... 1번
void f(char x) ... 2번
메인에서 f(1) 이 있다. 스태틱이라면 컴파일 시 1번이다! 1번으로 바꿔놓자. ->시험에 나온다잉.
다이나믹이라면 런타임에서 실행할 때 1번이다! 1번으로 실행.
자바 언어에서
A x = new B();
x.f();
호출 시 class A {void f()} 와 class B extends {void f()} 중 후자가 선택된다.
C++에서는 스태틱 폴리모피즘이다. 그래서 전자가 선택된다.
자바는 x에 담겨있는 객체가 어디에 담겨있는가 확인해서 함수를 B에서 호출한다. C++은 x에 담겨있는 객체가 무엇인지 모른다. 타입만 알기 때문에 A타입인 것만 알아서 전자를 호출한다.
그렇다면 후자를 원한다면 C++에서도? 그러면 B x = new B();를 하면 된다. 근데 폴리모피즘을 더 극대화 하고 싶다면. virtual이라는 키워드를 붙인다. 자바와 동일하게 다이나믹 폴리모피즘을 적용하게 된다. class A { virtual void f() } 을 하면 된다.
A:B 상속을 생각하면 A가 자식이고, B가 부모이다.
A: 버스 / B : 자동차 라고 생각하면 벤다이어그램은 B가 A를 포함하는 그림이 나온다.(추가되는 부여 특성 및 행동을 생각한 게 아님.)의미론적이다.
- Car x = new car
- Car x = new Bus
Bus x = new Car벤다이어그램을 잘 생각하자.- Bus x = new Bus
For Elegant Programming Style (C++ specific)
스타일 가이드 : 코드 짤 때 이렇게 짜세요.
회사에서 사용하는 스타일 가이드도 있다. 코드에 유지 보수 측면에서 좋다. 다른 사람도 보기 편한 코드를 작성할 수 있다. cpplint를 이용해서 깔끔하게 작성해보자.
Linter(예시 : cpplint)가 돌아가서 코드 스타일을 수정하라고 알려준다.
회사에서 코드를 제출하면 Linter가 돌아가고, 동료들에게도 전해진다. 피드백(스타일가이드는 린터, 기능 측면은 동료.) LGTM(Looks Good To Me)를 달아준다. readability를 보고 또 피드백을 준다. 이후 피드백을 다 받고 수정하여 회사 코드 베이스에 들어가게 된다.
스타일가이드는 구글을 따른다.
Naming Convention (이름을 어떻게 작성할까.)
변수 이름에 의미 있게. iterator 는 의미 없이 해도 된다.
변수 이름에 약자를 쓰는 것 좋지 않다. 금시. Full Name으로 써라.
약자를 사용해도 누구나 다 알 수 있는 흔한 약자라면 괜찮다. univ - university 인 거 알잖아.
파일 이름 다 소문자, 하이픈이나 언더바로 연결. 프로젝트에서 모든 파일에 연결 시 똑같은 양식으로 해야한다. '-', '_' 둘 중 하나만 쓰자.
클래스 이름, 타입을 정할 때, 파스칼 케이스를 사용한다. StaticAnalysis 이렇게. 언더바 사용하지 않는다. 모든 단어의 첫 철자는 대문자.
스네이크 케이스 안 돼! 누가봐도 클래스인 걸 알려면 pascal case.
변수 이름은 C++에서 스네이크 케이스를 사용. 언더바로 연결하자.
멤버 필드를 선언할 때, 끝에 언더스코어를 달아주자. 로컬 변수와 다르게 생겨야 사용하기 편하다.
스트럭트 경우에는 그냥 똑같이 변수 이름 사용한다.
클래스와 스트럭트의 차이점.
사실 똑같다. 클래스는 멤버 필드가 기본적으로 private이다. public이라고 얘기 안 하면 private. 스트럭트는 기본적으로 public이다.
기본적으로 자료형을 나타낸다. Struct Point { int x, y;} 스트럭트는 일반적으로 멤버 펑션을 갖지 않는다. 갖게 되면 클래스 사용.
const 사용 시 보통 변수 앞에 k를 붙이고 카멜 케이스를 사용하여 이름을 붙인다. const int kDaysInWeek;
함수 이름도 파스칼 케이스를 사용한다. 접근 함수는 필드 이름과 똑같이 정해서 한다. result_를 반환하는 함수 result()
설정하는 set 함수는 set_result(int result)
주석
주석은 일관적이어야 한다. /* */을 쓰든 //을 쓰든 하나만 써라.
클래스에 주석을 달 때, (과제에서는 할 필요 없다.) 이 클래스가 무엇인지 설명하는 주석. 최대한 간결. 그 다음에는 어떻게 사용하는지.
이 함수가 불릴 때 무엇을 만족해야하는지 pre-condition을 적어줘야 한다.
불확실한 변수를 설명하는 주석을 달아야한다.
테스트 주도 개발이 뭔지.
요구사항을 다 읽어보고 프로그래밍 하고 테스트 하고 다시 프로그래밍 하고 테스트 하고 ...
Test Driven development는 테스트부터 한다. 테스트를 먼저 쓴다. 테스트를 통과할 때 까지 계속 프로그래밍 짜기. 하나씩 테스트를 통과시켜서 프로그램을 짜는 것.
테스트 케이스 tc에 대한 오라클(정답)이 있다. add(1,3) = 4 라는 것을 통과해야 한다.그 다음 다른 tc인 add(4,7) = 11을 통과하러 가자. 이전의 테스트 케이스는 지우지 않는다. 개발하는 동안 테스트 케이스는 계속 증가한다. 테스팅 프레임워크를 같이 사용한다.
뭐가 성공했고, 실패했는지 알려주는 테스팅 프레임워크가 있다. 구글 테스트를 사용. 테스트를 짜고 그 테스트를 풀어나가는 형식으로 숙제를 풀기. 숙제는 테스트까지 제출해야한다. regression test 회귀 테스트라는 것도 있다. 미리 습관을 들이자.
'[Computer Science] -보호글 > [객체지향설계]' 카테고리의 다른 글
[객체지향설계] 10/03 이론 (0) | 2023.10.23 |
---|---|
[객체지향설계] 10/17 이론 (1) | 2023.10.17 |
[객체지향설계] 09/26 이론 (0) | 2023.09.26 |
[객체지향설계] 9/19 이론 (0) | 2023.09.19 |
[객체지향설계]9/4 오리엔테이션 (0) | 2023.09.05 |