VEDA 2주차 내용 정리

2025.10.27 ~ 2025.10.31

2주차 기록-1에 이어 오늘은 C++언어 학습과 C언어와의 차이 그리고 드디어 받았다! 굿즈 소개편과 함께 한주를 마무리하도록 하겠습니다.

C++이란?

객체 중심으로 데이터에 포커스가 맞춰지며 발전하게 된 프로그래밍 언어의 한 형태입니다...!
그렇다면 무엇이 추가되었는가?

발전 사항

  • 클래스 추가
  • 메모리 관리 용이 ( new, delete 키워드 지원)
  • 레퍼런스 → 포인터
  • 가상 함수와 오버로딩 → 다형성 지원

장점
1. 객체 지향 프로그래밍
2. 저수준 접근과 메모리 직접 관리
3. 데이터 추상화와 범용성

이러한 장점과 발전사항이 있다는 것만 알고 기본문법으로 우선 넘어가봅시다!
C언어와 차이점 위주로 정리하겠습니다.

변수와 연산자

객체란? 처리할 데이터와 처리 방법을 객체라는 논리 단위로 모두 포함하는 것입니다.
그러면 객체의 관점에서 입출력, 변수를 어떻게 처리하는지 알아봅시다.

C++ 에서 입출력 → std::cout , std::cin 을 사용

헤더 파일 #include<iostream>

>> 입출력 스트림 연산자

네임 스페이스 → 소속을 알림 ✳️ using namespace std

⇒ 이는 std를 생략할 수 있게 한다.

  • 내부 식별자에 범위를 부여해 여러 라이브러리를 사용할 때 이름이 충돌하는 것을 방지한다.
  • 그냥 std::cout 의 이런 형태로 사용하는게 낫다. ❓why? c++라이브러리가 업데이트되어 내가 선언한 변수나 함수와 중복될 때 문제가 발생할 수 있음.

cout : 표준 출력 스트림 객체

endl : \n 과 같음 , 출력 버퍼를 비우는 역할이기도 함 [manipulator]

cin : 입력된 데이터의 형식을 확인하고 변수에 입력값 저장. [ 표준 입력 스트림 객체]

데이터 형식

기본적으로 C언어와 동일하지만 bool형이 추가 되었습니다.

  • char -> wchar_t라는 와이드 문자형이 존재합니다.
구분charwchar_t
인코딩 방식멀티바이트유니코드
단일 문자 크기1 또는 2byte
영문, 숫자는 1byte
한글, 한자는 2byte
2byte
(GCC에서는 4byte)
문자열유니코드를 제외한 문자열와이드 문자
UTF-16으로 인코딩된 문자열

유니코드 문자열을 넣기 위해서는 L”문자열” 처럼 지정해야한다

wchar_t message_korean[] = L"반갑다잉"; //L"문자열" 사용

구조체 -> c언어와 달리 C++에서는 typedef로 했던 것을 간단하게 이뤄냄

struct Person {

int weight;

}
 Person p; 

포인터와 메모리

자 큰거 옵니다. C언어에서는 동적 할당으로 free(), malloc()이 있었지만 C++에서는 newdelete가 추가되었습니다.

동적 메모리 할당

new 자료형 *변수_이름 = new 자료형;

delete 변수_이름;

배열의 동적 할당에서는 크기를 지정해야 한다. delete[] pt_int_array_value 동적 메모리 해제

반드시 배열 delete를 해야함. ⇒>[ ]를 빼먹으면 정수 하나만큼 삭제 (메모리 누수 발생)

동적 메모리 : heap 메모리에 할당 ( 함수 종료 등과 무관하게 유지) → 할당 영역이 크고 개발자가 직접 관리 해야함

일반 변수 : 스택 메모리에 할당( 함수 종료 시 자동으로 소멸) 할당 가능 영역이 적고 이를 초과시 OS가 강제 종료하기도 함

void foo(){
	int *pt = nullptr; //포인터 변수 선언 및 nullptr로 초기화( 포인터 변수는 지역변수)
	pt = new int[10]; // 동적 메모리 할당
} //함수 종료 -> *pt 소멸 int[10]은 남아있음

‼️새로운 키워드 함수가 두가지 추가되었지만 기존의 free,malloc함수도 사용할 수 있으며 이미 해제한 포인터를 다시 delete or free를 하게 되면 오류가 날 수 있음을 기억하고 넘어갑시다!

string
string 자료형 또한 C++에서 추가된 것으로 기존 C언어에서는 char 배열로 처리를 해주었습니다.
하지만 문자열 자료형이 추가되었고 +연산을 통해서 문자열 접합 연산을 수행할 수 있습니다 .
char = > ' '
string => " "
로 문자와 문자열을 구분하는 것을 기억하며 넘어가도록 하겠습니다.

정적 변수와 상수 변수

정적 변수 static

  • 자동 지속 : 지역 변수가 선언된 {}로 둘러 쌓인 블록을 벗어나면 소멸되는 것
  • 정적 지속 : 지역 변수에 static 키워드를 사용하면 전역에서 사용할 수 있는 정적 지속으로 변경
    • 변수 선언 시 생성되는 것이 아닌 프로그램이 시작되면 생성되고, 프로그램이 종료되면 소멸됨.

정적 변수의 수명 주기가 지역 변수와 다른 이유
지역 변수는 stack영역에 저장되지만 정적 변수는 전역 변수와 같이 데이터 영역에 저장된다.
데이터 영역 : 프로그램이 시작될 때 할당되며 종료할 때 해제됨

상수 변수 const
변하지 않는 값 상수
const 키워드로 변수를 상수화 → 반드시 선언과 함께 초기화를 해주어야함.
상수 변수에는 초기화 된 이후에 값을 대입할 수 없음
⭐포인터 변수의 상수화 → 포인터가 가리키는 주소의 값을 바꾸지 못하게 함

int a =0;
const int *ptr = &a;
a=1; //가능
*ptr =2; // 컴파일 오류 발생 -> 포인터를 통한 값 변경이 불가능

=> 함수에서 const 포인터 변수를 자주 이용하니 기억을 꼭 하도록 하겠습니다.☺️

레퍼런스 변수

변수에 다른 이름(별칭)을 부여합니다. 값에 의한 호출 시에는 값이 매개변수로 복사되어 함수 영역에서 새로운 변수로 쓰이지마 레퍼런스 변수를 사용하면 원본 변수를 참조하는 효과를 얻을 수 있습니다.

차이
주소 연산자 -> R-value에 사용
레퍼런스 연산자 => L-value에 붙여 자료형에 사용된다.

이렇게 실제 변수는 하나지만 두개의 이름으로 활용되게 됩니다.

✅포인터 변수와 동일한 효과를 가지지만 그 크기에서 차이를 가집니다. 포인터 변수는 64bit 컴퓨터에서 8바이트의 크기를 가지지만 레퍼런스 변수는 자료형의 크기를 가집니다.!!

⚠️주의

  1. 레퍼런스 변수는 선언 후 반드시 참조할 원본 변수를 지정해야한다
    • 단독 초기화 불가능 int &ref_val ; → 컴파일 오류
  2. 참조할 대상이 지정된 레퍼런스 변수는 다른 변수를 참조하도록 변경할 수 없다.
  3. 레퍼런스 변수는 상수를 참조할 수 없다
    • 상수 참조 불가능 int &ref_int = 50; → 컴파일 오류
    • const상수로 만든다면 컴파일은 통과가 되지만 의미가 없음.

예외 처리하기

try, catch, throw : 예외가 발생했을 때 프로그램의 제어 흐름을 변경하고 예외를 처리

  • try : 예외가 발생할 수 있는 코드 블록을 {}으로 감싸 준다.

  • catch : throw 로 던진 예외를 받아서 처리한다.

    • 예외 형식 명시 가능

      catch(…) : 명시하지 않은 나머지 모든 예외를 받아서 처리할 때 사용.

  • throw : 예외를 catch블록으로 던진다

    • catch로 보낼 예외 형식과 일치
      이처럼 예외처리 구문을 이용해 컴파일과 디버깅 시에 유용하게 사용할 수 있습니다. 이는 직접 사용하면서 익히는게 효과적이라 생각해 간단하게 특징만 알고 넘어가겠습니다.

    +) 끝까지 catch문이 없으면 OS단에서 처리 -> 프로그램 종료!
    +) 예외를 전달하는 순서가 스택에 쌓인 역순이다.

객체 지향 프로그래밍

프로그래밍 패러다임에서 비구조적 프로그래밍 -> 절차적 프로그래밍을 거쳐 지금의 객체 지향 프로그래밍까지 오게 되었습니다.

기존 패러다임의 문제점

  • 프로시저의 다층 구조를 표현 불가
  • 전역 구조에 대한 접근을 막을 수가 없음
  • 논리 구조에 대한 이해 부족으로 접근하지 말아야할 프로시저에 접근 가능

이런 문제점을 해결하고자 객체 지향 프로그래밍이 등장했습니다.

필요성

  1. 현실 모델링
    추상화 : 현실의 대상을 논리적으로 구조화하기 위해 일반화, 단순화하는 과정
    모델링의 최소 단위 : 객체 ⇒ 역할, 포함 관계, 사용 관계도 정의 필요.
  2. 논리적 계층 관계 표현
    is -a 관계 : 이는 상호 교환이 성립 [일반화]
    상속 : 일반화 중에서 상위 객체의 속성을 그대로 물려받아 새로운 객체의 특성을 추가
  3. 접근 제어
    → 객체 간 접근 제어 ( 접근할 수 있는 권한을 필요에 따라 한정)
    이벤트 사용 관계 ex) 출력 조절기 - 피스톤 ⇒ 출력 조절기가 피스톤을 직접 움직이는 것이 아님

객체 지향 프로그래밍의 특징

  1. 추상화:모델링을 하면서 객체로 만들 때 어떤 부류에서 불필요한 요소는 배제하고 공통된 특징만 추출하는 것
  2. 다형성:상속 받은 객체가 자신의 특성을 반영해 다르게 동작 → 같은 함수가 다르게 동작
  3. 캡슐화:복잡한 내부 기능을 묶어 외부에서 불필요한 정보를 감추는 것(동작 + 데이터 숨김)
  4. 상속성⭐️ :여러 계층으로 구성 가능 + 고유의 특성을 추가

클래스와 인스턴스

C++ 언어에서 새로 등장한 클래스라는 개념은 구조체의 필요성을 잊게 해주었습니다. 더 많은 것을 표현할 수 있고 다양한 표현이 가능해졌습니다.

  • 클래스: 객체가 포함하는 데이터와 함수를 정의하는 문법적인 요소 (데이터 형식)
    멤버 변수와 메소드(멤버 함수)를 가짐
    접근 제어를 위해 private , public 키워드 사용
  • 객체 : 특정 클래스를 사용할 수 있도록 만든 문법

클래스 정의 문법

class gs_engine(클래스 이름) : public ic_engine(부모 클래스) {

public:
	gs_engine(); //생성자
	~gs_engine(); // 소멸자
private:(접근 지정자)
  void acceleration_output() override { increasing_fuel(); }; (멤버 함수 선언과 구현)
  void reduce_output() override { decreasing_fuel(); };
  void increasing_fuel() { increasing_piston_speed(); };
  void decreasing_fuel() { decreasing_piston_speed(); };
  void increasing_piston_speed() { cout << "increasing_piston_speed" << endl; };
  void decreasing_piston_speed() { cout << "decreasing_piston_speed" << endl; };
  
  int current_fuel;
  int piston_speed; //=> 멤버 변수 선언 보통 private으로 선언
};
// 👆클래스 선언
//👇멤버 함수 정의부 

  //멤버 함수 네임스페이스
void gs_engine::acceleration_output(){
	increasing_fuel();
	current_fuel++;
}

⚠️접근 지정자를 명시하지 않았다면 private으로 간주

  • 인스턴스 : 클래스 정의에 따라 메모리에 실체화된 객체의 형태
    이는 일단 객체 == 인스턴스로 생각하고 넘어가겠습니다
    . => 멤버 접근 연산자
    상속과 다형성
    c++에서는 다중 상속을 지원하여 이는 Diamond of Death 현상이 발생할 수 있습니다.
    이와 관련된 내용은 아래의 블로그에 정리되어 있으니 확인해보시길 바랍니다.
    다중 상속의 문제점
    이를 해결하기 위해서는 Virtual Inheritance의 개념이 존재하지만 우선 이후에 다시 차차 정리해서 올리도록 하겠습니다!

부모 - 자식 클래스 간의 포인터가 있을 때 어떤 클래스가 어떤 클래스를 가리킬 수 있는가?

  • 자식 클래스의 포인터를 부모 클래스 포인터에 넣는 것은 자연스러운 형변환

    • 부모* = new 자식 ⇒ 삼각형은 도형이다 → 맞음 ⭕

    • 자식 * = new 부모 ⇒ 도형은 삼각형이다 → 틀림 ❌

      Shape *ptr = new Triangle() ; //=> 맞는 선언
      Triangle *t_ptr = new Shape(); // => 틀린 선언

      동적 할당 → runtime casting
      compile casting → 양쪽의 타입이 다를 경우 L-value형태로 형변환 할 것인지 확인

      		`Shape *ptr = new Triangle() ;`  ⇒ triangle 너 부모가 shape야?  검사.

      ⭐⭐⭐⭐⭐

      Shape *ptr = new Triangle() ; // compile과 runtime 둘다 문제 없
      Triangle *t_ptr = ptr; 
      // 이건 맞는거냐?  complie시에는 shape의 부모클래스가 triangle이냐? 아님. 틀림
      
      //runtime 관점에서는 맞음 
      //그러면 명시적 casting을 사용해서 형변환을 하면 된다.
      Triangle *t_ptr = (Triangle *)ptr; //오류가 발생할 수는 있지만 프로그래머가 맞춰줌.
      
      ------------------------------------------
      Shape *ptr = new Shape() ;
      Triangle *t_ptr = (Triangle *)ptr;
      //이 경우는 컴파일시에는 문제 없음
      //runtime에서 문제 발생  shape에는 없는 요소를 찾아서 문제 발생
      			```
      			이는 여태 2주차까지의 포인터와 메모리 영역에 대한 이해가 필요한 문제입니다. 천천히 음미하면서 소화시키도록 하겠습니다 ㅠ😭ㅠ
      
      

2주차의 어려웠던 내용

포인터와 배열의 차이점을 조금 더 명확이 이해해야할 것 같다.이것이 클래스의 상속으로 이어져 다형성과 상속 관계에서도 헷갈리는 부분이 존재했다.
다중 포인터와 포인터의 개념에 대해 조금 더 명확하게 이해할 필요가 있다고 느껴졌다.
입출력 형식을 헷갈리지 않게 외우고 복습을 진행하자!!

막간을 이용한 2주차 VEDA 점심 식당 후기

2주차를 진행하는 지금... 아직까지 점심 G.O.A.T는 맥날이다. 하지만 2주차의 마지막날 희망을 보았다.
그것은 젠슨황과 이재용, 정의선 회장도 애용하는 깐.부.치.킨...!

물론 그건 삼성역점이지만 깐부치킨 양재역점에 엄청난 녀석이 숨어있었다. 치킨집에서 하는 한식뷔페라..
반신반의하는 마음으로 갔지만 맛있는 한끼를 하고 나올 수 있었다. 살짝 먼 감이 없지 않아 있지만 가끔씩 가기에는 좋은 듯하다. 무슨 메뉴가 나올까 기대하는 마음으로 ..ㅎ

앞으로 더 많은 점심 맛집을 찾아 공유하겠읍니다.. 나의 점심메이트들 고맙습니다.😇

VEDA 3기 굿즈.

2주차가 되어서 VEDA의 굿즈를 수령했습니다.

왓!

기대를 하면서 보따리를 풀어보니 만족😀
뙇

앞으로도 정진..

3주차 정리를 가지고 돌아오겠습니다.. SEE YOU. AGAIN.!

profile
세상의 어려운 문제를 해결하자

0개의 댓글