프로그래밍 언어/C++

    C++ 위임 생성자 (delegating constructor)

    위임 생성자는 특정 생성자를 호출하기 전 다른 생성자를 먼저 호출하는 것이다. 상속 받을 때처럼 : 기호를 써야한다. member-initializer-list(멤버 초기화 리스트)를 가질 수가 없다. 즉 아래에 mX(X), mY(Y) 에서 다른 생성자 호출이 불가능하다. Parent(int X) : Parent() 여기서는 Parent가 먼저 호출되고 int형 파라미터 들어간 생성자가 호출 된다. 자식 클래스에서 또한 부모 클래스의 생성자를 쓸 수가 있다, 부모 생성자에선 자식 생성자를 대리로 호출하는건 불가능하다. 마찬가지로 부모 클래스의 생성자가 호출 되고 자식 클래스의 생성자가 호출된다. #include #include using namespace std; class Parent { int mX ..

    C++ NULL과 nullptr의 차이

    1. int* 포인터에 정수 값 대입 int Integer, *Pointer; void print(int ptr) { Integer = ptr; cout

    C++ 가변 길이 배열 (Variable Length Array)

    가변 길이 배열은 2차원 배열에서 각각의 첫번째 원소에 다른 길이의 배열을 담는 것이다. 아래는 C 스타일이다. #include using namespace std; int main() { // ------- 고정 길이 배열 ------- int arr[10]{ 5 }; for (int i = 1; i < 10; i++) arr[i] = arr[i - 1] + 5; // ------- 가변 길이 배열 (C 스타일 배열 사용) ------- int arr2[3]{ 1, 2, 3 }; int arr3[5]{ 4, 5, 6, 7, 8 }; int* variableArr[3]; *variableArr = arr; *(variableArr + 1) = arr2; *(variableArr + 2) = arr3; c..

    C/C++ 포인터 역참조 (deference)

    배열의 포인터는 크게 *(단일 포인터) 또는 **(이중 포인터)로 받을 수가 있다. 역참조는 해당 포인터가 자기 자신을 가리키게끔 하는건데 예시로 *ptr이면 ptr-> 성질과 비슷하다, 즉 null 포인터일 시 당연히 뻥난다. *ptr는 arr의 시작 주소를 받아내고 전체 배열의 접근이 가능하다. *ptr2는 단일 주소 포인터다, 오직 할당받은 &배열[인덱스]에만 접근 가능하다. *(ptr3)[10] 이건 이중 포인터로 받아내는 것이다, 2차원 배열 또는 포인터 배열로 접근할 수가 있다. #include using namespace std; int main() { int arr[10]{ 5 }; for (int i = 1; i < 10; i++) arr[i] = arr[i - 1] + 5; int* p..

    C++ 얕은 복사 깊은 복사 (Shallow/Deep Copy)

    아래와 같이 코드를 작성하면 a1 객체와 a2 객체가 서로 같은 int형에 대한 포인터 변수를 공유하기 때문에 이미 해제된걸 재해제 하기 때문이다. #include using namespace std; class A { int* ptr = nullptr; public: A() { ptr = new int(); } A(const A& Ref) { this->ptr = Ref.ptr; } ~A() { delete ptr; } }; int main() { // 기본 생성자 호출 A a1; // 복사 생성자 호출 A a2(a1); } 이를 해결하기 위해선 ptr를 참조 대상값 가지고서 재 할당 해줘야한다. #include using namespace std; class A { int* ptr = nullptr;..

    C++ 임시 객체 (Temporary Object)

    임시 객체를 r-value로 알고있는데 이는 틀렸다, 임시 객체 또한 const&로 파라미터로 넘길 수가 있다. r-value move semantics #include using namespace std; class Vector { public: float x = 0, y = 0, z = 0; public: Vector(float Val) : x(Val),y(Val),z(Val) { } static float Length(const Vector& Vec) { return Vec.x + Vec.y + Vec.z; } }; int main() { cout

    C++ 부모 클래스 함수 호출과 오버라이딩 (override)

    오버라이딩 핵심 개념 오버라이딩은 부모 클래스에서 정의한걸 재정의 하는 것이다. 추상클래스 (순수 가상 함수) 참조 아래와 같이 부모 클래스에선 virtual 키워드를 붙여준 뒤 함수를 정의하고 자식 클래스에서 재정의 하는 것이다. virtual로 시작 (생략 가능) 그리고 마지막엔 override 붙일 수가 있다. (이것 또한 생략 가능) #include using namespace std; class Parent { int mVal = 0; public: virtual void Fn1() { } virtual void Fn2() { } virtual void Fn3() { } virtual void Fn4() = 0; }; class Child : public Parent { public: void ..

    C++ 자기 자신 참조 (this)

    아래 코드를 살펴보면 Set 함수에서 멤버 변수 val에 파라미터로 넘어오는 값을 대입하고자 하는데 공교롭게도 val을 파라미터로 넘어오는 값으로 인식한다 val은 초기화가 안됐으므로 쓰레기값이 출력될거다. #include using namespace std; class Parent { int val; public: void Set(int val) { val = val; } int Get() const { return val; } }; int main() { Parent parent; parent.Set(10); cout

    C++ 추상 클래스 / 순수 가상 함수 (Pure Virtual Function)

    순수 가상함수란 선언(declaration)만 있고 구현(definition)이 없는 가상 함수다. virtual void Func() = 0; 추상 클래스 위와 같은 순수 가상함수를 하나라도 가지고 있는 클래스를 추상클래스(abstract class)라고 한다. 추상 클래스는 객체를 생성할 수 없다. 추상 클래스는 멤버 함수의 원형만을 정의하고 그 구현은 자식 클래스에서 하게 된다. 추상 클래스를 상속받는 자식 클래스는 반드시 순수 가상함수를 오버라이딩 하여 재정의 해야만 한다. 그렇지 않다면 아래 그림과 같이 컴파일 오류가 난다. 이렇게 추상클래스를 활용하면 파생클래스에서 순수 가상함수를 재정의 하게끔 강제할 수 있다. #include using namespace std; class Parent { ..

    C++ 클래스 접근 제한자 (Access Modifier)

    public, private, protected 바로 이 3가지이고 쓰여지는 이유는 객체지향 프로그래밍의 중요한 개념 중 하나는 데이터 숨김(은닉) 때문이다. 클래스 내에 멤버에 대한 접근 제한자를 두지 않으면 기본적으로 private이다. 구조체 멤버에 대한 기본적인 접근 제한자는 public이다. friend 키워드는 private와 protected의 원칙을 깨트림으로서 코드의 직관성과 흐름 파악을 복잡하게하는 goto같은 존재이다. friend 관련 글 참고 public public으로 선언된 데이터 멤버 및 멤버함수는 . 연산자를 사용하여 프로그램의 아무곳에서나 액세스 할 수 있다. private 클래스 멤버를 private으로 선언하면 해당 멤버는 오직 클래스 내부에서 접근할 수 있다, 외부의..