TIL/TIS 211124

gyeon·2021년 11월 24일
0

TIL/TIS

목록 보기
9/14

오버로딩

C++에서는 C와 다르게 오버로딩이 허용된다. 다만 기존에 C에서 쓰던 함수들은 오버로딩이 당연히 안된다.
오버로딩된 함수 호출시 다음과 같은 우선순위를 가진다.

  • 1순위 : 매개변수 타입이 정확히 일치하는 함수
  • 2순위 : 형변환을 가능한 매가변수
    char, unsigned char, short -> int
    unsigned short -> int or unsigned int
    flout -> double
    enum -> int
  • 3순위 : 좀 더 표괄적인 형변환수행
  • 4순위 : 유저가 정의한 타입 변환을 통해 일치하는 것을 찾음

위의 단계를 거쳐도 없으면 오류 생성. 출처 : 모두의 코드

생성자

#include <iostream>

class TestClass {
    private:
        // 멤버 변수
        int var1;
    
    public:
        // 생성자. 
        // C++ 11부터 디폴트 생성자를 다음과 같이 선언할수 있게 됨.
        TestClass() = default;
        TestClass(int var1);
        // 소멸자
        ~TestClass();
        // 멤버 함수
        void setVar1(int var1);
        int getVar1();
};

TestClass::TestClass() {
    var1 = 42;
}

TestClass::TestClass(int var1) {
    this->var1 = var1;
}

TestClass::TestClass() {
    // 그냥 소멸자 보여줄라고 만들어봄..
    ;
}

void TestClass::setVar1(int var1) {
    this->var1 = var1;
}

int TestClass::getVar1() {
    return this->var1;
}

복사생성자

자신과 같은 클래스 타입의 인스턴스의 참조를 매개변수로 받아서, 이를 바탕으로 자기 자신을 초기화하는 생성자. 아래와 같은 형태이다.

class TestClass {
	...
    public:
        // 복사 생성자
        TestClass(const TestClass& src);
        ...
}

복사생성자를 호출하고자 한다면
1. TestClass test_class = TestClass(src);
2. TestClass test_class = src;
디폴트 복사 생성자
복사생성자를 만들지 않아도 컴파일러가 자동으로 복사생성자를 생성해주는데, 이를 디폴트 복사생성자라고 한다. 디폴트 복사생성자는 입력받은 인스턴스의 모든 맴버 변수의 값과 똑같이 초기화를 한다.
같은 동작 방식으로 동작할 것이다.

#include <iostream>
#include <string.h>
using std::string;

class TestClass {
    public:
        // 포인터 출력을 위해 일부러
        int var1;
        char *var2;
        int get_var1(){return var1;};
        void set_var1(int var1);
        char * get_var2(){return var2;};
        void set_var2(char *var2);
        TestClass(int var1, const char *var2) {
            this->var1 = var1;
            this->var2 = new char[strlen(var2) + 1];
            strcpy(this->var2, var2);
        }

};

int main() {
    string str("gyeon");
    TestClass *tc = new TestClass(42, str.c_str());
    // 디폴트 복사 생성자 이용
    TestClass *tc2 = tc;
    std::cout << tc2->get_var2() << "\t: " << tc2->get_var1() << std::endl;
    std::cout << (int *)(tc->var2) << " , " << (int *)(tc2->var2) << std::endl;
    return 0;
} 

gyeon : 42
0xff7c08 , 0xff7c08

다음과 같은 경우 문자열의 포인터가 같은 곳을 가르킨다. 즉, 클래스 내부에 포인터가 있는 경우, 포인터의 값 까지 복사되어 delete등 시 문제가 발생할 가능성이 있다.
해결
1. 디폭트 복사 생성자 대신, 직접 복사생성자를 선언한다.
위의 포인터 문제의 경우, 포인터인 맴버변수는 동적할당후 얋은 복사

TestClass::TestClass(const TestClass& src) {
    this->var1 = src.var1;
    this->var2 = new char[strlen(src.var2) + 1];
    strcpy(this->var2, src.var2);
    ...
}
  1. 조심해서 잘 사용한다...(복사된 인스턴스를 나중에 delete한다던가).

C++ new & delete

C++에서는 malloc, free대신 new, delete를 사용한다.

#include <iostream>

int main() {
	int 
}
  • malloc/free은 함수지만, new/delete는 연산자이다.
  • new/delete는 생성/소멸자를 호출한다.
  • new/delete는 new->delete->new해줘야한다. malloc/free는 realloc을 쓰면 된다(근데 내부적으로 똑같이 동작하고 있을 가능성이 있는데..).
  • malloc/free는 type-safe로, 할당한 자료형(객체)를 반환한다.
  • malloc/free는 에러가 발생하면 throw를 한다(malloc은 알다싶이 null반환).
  • malloc/free은 기본 자료형(POD, C에 호환되는 자료형들, 함수x)만 동적할당이 가능하지만, new/delete는 클래스(함수를 포함)까지 동적할당 할 수 있다.
    참고1, 참고2
profile
백엔드와 서버 in 42Seoul

0개의 댓글