C++ ! A부터 Z까지 !

파이톨치·2022년 6월 10일
3

대학수업

목록 보기
31/32
post-thumbnail

C++

C++은 많이들 배우는 언어이다. 나도 이번 학기 동안 C++과 객체지향에 대해 배웠고 지금 그것을 정리하고자 한다. 내가 나중에 봤을 때 어떤 내용을 했었는지 기억에 남았으면 좋겠고, 내 머리에도 그것이 남았으면 좋겠다.

우선 c++은 c언어를 기반으로 제작된 것이 이름에서 부터 느껴진다. 이러한 c++을 통해서 우리는 객체지향에 대해 이해할 것이다. 프로그래밍은 현재 객체지향을 많이 사용하기 때문이다.

기초적인 내용

변수

우선 간단한 내용부터 살펴볼 것인데 그것은 바로 변수이다.

수학에서 변수는 변하는 값이다. 2차원에서 변수는 보통 x, y 로 잡고 이것은 변하는 수로 이것을 통해 차원을 정의한다.

프로그래밍에서도 이러한 변수가 존재한다.

변수를 선언할 때는 변수의 타입과 이름을 정해주어야 한다.

변수의 타입이 뭔지 물어볼 수 있다. 변수의 타입은 정수, 실수, 문자, 문장 등으로 구분된다.

이를 컴퓨터 (컴파일러)가 알아듣기 쉽게 만들면, int, float, char, string 이다.

때문에 int IntVar;와 같은 형식으로 프로그래밍을 해주면 변수의 선언이 된다.

변수는 변하는 값이기에 변수에 값을 저장해줄 수 있다.

IntVar = 10; 과 같은 형식으로 값을 넣어줄 수 있다. 수학과 다르게 = 는 대입 연산자이다.

정수형에 실수형을 넣으면 어떻게 되나요?

예를 드렁서 IntVar = 10.99; 를 하면 어떻게 될까? 에러가 날까?
이는 컴파일러가 알아서 처리해 준다. 소수점을 버리는 형식으로 말이다.
쉽게 생각해서 10.99를 정수형으로 형 변환을 시켜서 저장해 준 것이다.

형 변환 static_cast

17.0 / 5의 값은 무엇일까요?

이 경우에는 3.4가 된다. 왜냐고 물을 수 있다. 뒤에 것이 정수 아닌가? 이러한 경우에 실수의 힘이 더 세기 때문에 5가 실수가 되면서 실수 연산이 된다.

이러한 것을 형 변환이라고 하는데 위의 경우에는 자동으로 형 변환이 된 것이다.

이러한 형 변환을 인위적으로 해줄 수 있는데 이는 static_cast <변수형> 변수 이름 과 같은 형식으로 해준다.

상수 const

10이나 10.99는 변수가 아니다. 이들은 변하지 않는 값이다. 10는 10이고 9는 9이다. 때문에 이런 변하지 않는 값들을 우리는 상수라고 부른다.

상수는 만들 수도 있다. 3.141592 와 같은 값은 변하지 않는 값이다. 이러한 값을 우리는 상수로 만들어 줄 수 있는데 const double PI = 3.141592와 같은 선언을 해주면 된다.

일반적인 변수를 만드는 방법 앞에 const를 붙이기만 하면 된다.

소수점 고정

float나 double을 그냥 출력하게 되면 뒤에 많은 소수점이 따라오는데 이를 없애는 방법이 있다.

cout.percision(2);를 해주면 소수점 2자리만 출력되는데 이는 반올림 된 값으로 나온다.

cout.setf(ios::fixed);를 해주면 위에서 선언한 자리수만큼 고정이 된다.

cout.setf(ios::showpoint);를 해주면 소수점을 표시해주게 된다.

int main () {
  double a = 30;
  double b = 10000.0;
  double pi = 3.1416;
  std::cout.precision (5);
  std::cout <<   std::showpoint << a << '\t' << b << '\t' << pi << '\n';
  std::cout << std::noshowpoint << a << '\t' << b << '\t' << pi << '\n';
  return 0;
}
30.000  10000.  3.1416
30      10000   3.1416

입력 cin

우리는 변수를 시시각각 내 마음에 드는 것으로 넣어주고 싶을 때가 있다.

cin >> var1 >> var2;와 같은 형식을 사용한다.
이때 띄어쓰기를 통해서 변수를 분리해 줄 수 있다. 아니면 엔터를 써도 된다. 이러한 whitespace를 통해서 변수를 나누어 받는다.

다양한 케이스 switch

swhitch (garade)
{
  case "a":
  case "A":
      cout << "you are A" << endl;
      break;
  case "b":
  case "B":
      cout << "you are B" << endl;
      break;
  default:
      cout << "???" << endl;
}

이런식으로 사용하면 원하는 위치로 점프할 수 있다.

삼항 연산자

if (n1 > n2)
	max = n1;
else
	max = n2;

이러한 선언 대신에 한줄로 간단하게 사용할 수 있는 것이 있다.

max = (n1 > n2) ? n1 : n2;

다음과 같은 식으로 깔끔한 코딩을 할 수 있다.

난수 생성 srand()

난수를 만드는 것은 사실 쉬운 일은 아니다. 패턴이 생길 수 있기 때문이다. 때문에 이러한 난수를 만드는 함수가 이미 구현되어 있다.

#include <time>

srand(time(0));

을 하면 난수를 생성할 수 있다.

오류를 잡는 방법 assert

#include <cassert>

이것을 사용하면 오류는 편하게 잡을 수 있다. 하지만 은근 고급기술이라 사실 초보자가 사용할 일은 많이 없을 수도 있다. 나도 초보자라 거의 써본 적이 없는데 사용은 간단하다.

내가 체크하고 싶은 부분에서, 원하는 결과가 맞는지 체크하기 위해서 사용한다.

assert(var > 10);

이런식으로 써두면 컴파일러가 맞으면 넘어가고 잘못되었으면 오류 창을 띄어주면서 디버깅하기 쉽게 만든다.

#define NDEBUG
#include <cassert>

를 해주게 되면 assert를 전체 다 끌 수 있다.

외부에서 파일 불러오기 inputStream

#include <fstream>

fstream inputStream;
inputStream.open("filename.txt");

inputStream >> var;
inputStream.close();

기본적인 내용

이제 기본적으로 알아야 하는 내용들이다. 이제부터 본격적으로 객체라는 것이 무엇인지에 대해서 생각을 해볼 것이다. 객체는 추상화를 기반으로 한 개념이다. 객체가 있고 그 객체는 이름과 기능이 있다. 예를 들어 자동차를 생각해보자. 자동차라는 객체는 이동한다는 기능이 있다. 뭐 부수적으로 엉덩이 온열 시트도 있을 것이다.

이러한 자동차는 종류가 다양하다. 아우디도 있고 현대도 있다. 자동차라는 큰 객체에서 보자면 이 둘의 기능은 동일하다.

내가 지금부터 할 내용들은 이러한 객체를 어떻게 만들고 사용하는지 살펴볼 것이다.

배열

배열은 객체는 아니지만 필요한 내용이라서 써 놓을 것이다.

학생들이 시험을 보면 점수를 받아 올 것이다. 그럼 학생들 마다 시험 점수를 저장해야하는데 어떻게 저장할 것인가?

배열이 없다면 김일등점수 = 99; 강꼴등점수 = 4; 전중간_점수 = 64; 이런식으로 될 것이다. 하지만 귀찮다. 너무 귀찮다. 때문에 배열을 사용하는 것이다.

int student_scores [] = {99, 4, 64};

끝이다. 이렇게 해주면 된다. 이렇게 해서 안에 적절한 인덱스만 넣어주면 되는 것이다.

함수에 넣을 때는 어떻게 할까?

함수에 넣을 때는 배열의 이름만 보내거나 특정 주소를 보내주면 된다. 하지만 이 때 배열의 크기 정보를 보내주어야한다는 것이 특징이다.

void fillup(int student_scores [], int size);

or

void fillup(int* student_scores, int size);

사용하는 방법은 다음과 같다.

fillup(student_scores, int size);

배열 이름을 대상으로 산술연산도 가능하다. 이 경우에는 배열의 다음 인덱스를 가리키거나 하는 형식으로 진행된다. 배열끼리의 더하기는 오류를 만들어내니 주의하자.

2차원 배열도 만들어낼 수 있다.

int array[2][2] = {
  {1,1,1},
  {2,2,2},
  {3,3,3}
}; 

이런식으로 만들어 주면 된다.

포인터

배열과 단짝 격인 친구가 포인터이다. 주소라는 개념이 들어가기 때문에 처음 공부하는 입장에서는 난감할 수 있다.

간단하게 생각해서 주소지를 들고 찾아 가는 것이다.

int var = 10;
int *p;
p = &var;

이렇게 쓰는데 p는 var를 참조하고 있는 것이다.

new

포인터에 변수를 할당해 주는게 아니라 새로운 공간을 만들어서 할당해 줄 수도 있는데 그것이 new 이다.

int * n ;
n = new int(17);

과 같은 형식으로 사용한다.

지울 때는

delete p;
p = NULL;

로 지운다.

이걸로 배열도 할당해 줄 수 있다.

typedef double* DoublePtr;
DoublePtr d;
d = new double[10];

과 같은 형식으로 사용한다.

지울 때는

delete [] d; 

좀 특이하니 조심하자.

참고
int* someFunc(); (O)
int [] someFunc(); (X)

-> 연산자

MyClass *p;
p = new MyClass;
p->grade = "A"; // == (*p).grade = "A";

this pointer

   month = mn;            // These three statements
   this->month = mn;      // are equivalent
   (*this).month = mn;

자기 자신을 가리키는 포인터가 내장되어 있어 이를 사용할 상황들이 있나보다.

구조체

그냥 정보를 담는 그릇이라고 생각하면 된다.

struct CDAccountV
{
	double balance;
    double balance;
    int term;
};

클래스

기본 뼈대

class Basic
{
public:
	// 생성자
    // copy 연산자
    // 산술 연산자
    // 소멸자
private:
	// 멤버 변수
};

상속

class 새
{
	'''
};

class 닭 : public 새 
{
	'''
};

생성자 소멸자는 상속되지 않고 나머지는 상속됨.

다시 정의 해서 덮을 수 있음.

고급 기술

생성자

// 기본
시급노동자 :: 시급노동자() : 노동자(), 시급(0), 노동시간(0)
{
	// 비었음
}


// 인자 주기
시급노동자 :: 시급노동자(string 이름,
string 번호, double 시급, double, 시간) : 노동자(이름, 번호), 시급(시급), 노동시간(시간)
{
	// 비었음
}

copy consturctor

자식& 자식:: 연산자 = (const 자식& 오른쪽)
{
	부모::연산자 = (오른쪽);
    '''
}

상속 시 오버라이딩을 위한 virtual

class 새
{
	'''
    
    virtual 울기()
    {
    	cout << "찌르르르" << endl;
    }
    
    '''
};

class 닭 : public 새 
{
	'''
    virtual 울기 ()
    {
    	cout << "꼬꼬 댁" << endl; 
    }
    '''
};

가상 함수와 추상 클래스

virtual void draw() = 0 ;

함수에 0을 넣는게 조금 이상해 보이지만 이렇게 선언한다고 한다.
그리고 이런 가상함수가 있는 것을 추상 클래스라고 한다.

넓은 범용성의 template <typename, T>

template<typename T>
Pair<T> :: Pair(T val1, T val2)
{
	first = val1;
    second = val2;
}

template<typename T>
void Pair<T> :: setFirst(T newVal)
{
	first = newVal;
}
Pair<int> score;
Pair<char> seats;

score.setFirst(3);

탬플릿도 상속이 될까?

template <typename T>
class Triple : public Pair<T>
{
	'''
}

STL

vector

#include <vector>
vector<int> cotainer;
cotainer.push_back(i);
vector<int>:: iterator p;

for (p=cotainer.begin(); p!= cotainer.end(); p++)
	cout << *p " ";

set

#include <set>

set<char> s;
s.insert('A');
s.insert('D');
s.insert('D');
s.insert('C');
s.insert('C');
s.insert('B');

set<char> :: const_iterator p;
for (p=s.begin(); p!=s.end(); p++)
	cout << *p << " " ;

=> A B C D
알아서 정렬되고 알아서 중복 제거 해 줌

map

map <string, string> planets;

planets["수"] = "쥰나 뜨겁다";
planets["금"] = "대기가 산성";
planets["지"] = "우리 별";

=> 금, 수, 지 (한글 생각한 순서)
얘도 알아서 정렬 됨.

정렬

std::sort (myvector.begin(), myvector.end());
std::sort (myvector.begin(), myvector.end(), myfunction);
//myfuction으로 역순으로 정렬도 가능;

탐색

where = find(mychar.begin((), mychar.end(), 'value');
profile
안알랴줌

0개의 댓글