반응형

 

this 포인터

- 자신을 가리키는 포인터이다.

- 객체의 0번째 멤버변수라고도 한다.

- 멤버함수에서 멤버변수에 접근하기 위해 사용한다.

class Test
{
private:
    int num1, num2;
public:
    void Add(int num1, int nm2)
    {
        //num1과 num2는 전부 지역변수이다.
        num1 = num1;
        num2 = num2;
        
        //그렇기 때문에 this 포인터로 멤버변수를 명시해준다.
        this->num1 = num1;
        this->num2 = num2;
    }
};
  • 변수명이 동일하면 제일 가까운 위치에 있는 변수로 취급된다.
  • 그렇기 때문에 this 포인터로 멤버변수를 구분해준다.
반응형

'Stack > C++' 카테고리의 다른 글

C++ 클래스 상속  (0) 2021.11.04
C++ 함수 오버로딩, Deault 매개변수  (0) 2021.10.24
C++ 복사 생성자 심화  (0) 2021.10.17
C++ 파일 입출력 ofstream, ifstream  (0) 2021.10.16
C++ 생성자, 복사생성자, 소멸자 (+ const)  (0) 2021.10.15
반응형

 

※ 들어가기에 앞서 참조자와 복사 생성자에 대한 사전 지식이 필요하니 다음 글을 참조

 

C++ 생성자, 소멸자 (+ const)

들어가기에 앞서... const - const 변수 : 해당 변수를 정보 변경이 불가능한 상수로 변환. - const 함수 : 해당 함수에서 const의 위치에 따라 정보의 변환을 막거나 반환값을 상수로 바꾼다. 1. const 변수

srdeveloper.tistory.com

 

C++ 참조자(Reference)

참조자 (Reference) - 할당된 어떤 하나의 메모리 공간에 다른 이름을 부여하는 것이다. ※ 별명이라고 생각해도 좋다. - 참조자는 변수 앞에 &를 붙여줌으로써 선언할 수 있다. ※ 이미 선언된 변수

srdeveloper.tistory.com


깊은 복사, 얕은 복사

- 깊은 복사 : 값이 복사되는 복사

- 얕은 복사 : 참조 값이 복사되는 복사

 

 

 

디폴트 복사 생성자의 문제점

- 앞서 생성자, 소멸자 포스팅에서 복사 생성자는 정의하지 않아도, 디폴트 복사 생성자가 자동으로 삽입된다.

- 하지만, 반드시 복사 생성자를 정의해야 하는 경우가 있다.

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;

class Test
{
private:
	
    char* cArr;
public:
    Test(const char* cArr)
    {
        int len = strlen(cArr) + 1;
        this->cArr = new char[len];
        strcpy(this->cArr, cArr);
    }
    void Show()
    {
        cout << "cArr : " << cArr << endl;
    }
    ~Test()
    {
        delete cArr;
        cout << "Called destructor" << endl;
    }
};

void main()
{
    Test t1("Test string");
    Test t2 = t1;
    t1.Show();
    t2.Show();
    
    //결과
    //cArr : Test string
    //cArr : Test string
    //Called destructor
}
  • 위와 같이 char 포인터를 디폴트 복사 생성자로 복사가 일어나게 되면 얕은 복사가 일어난다.
  • 즉, 참조값이 복사가 되기 때문에 t2객체와 t1객체의 cArr 포인터가 참조하는 문자열은 같다고 볼 수 있다.
  • 그렇기 때문에 어떤 객체의 소멸자에서 cArr이 참조하는 문자열을 delete로 할당해제 하면 남은 객체에서는 이미 지워진 문자열을 대상으로 delete 연산을 하기 때문에 문제가 된다.
  • 따라서 복사 생성자를 정의할때에는 이러한 문제가 발생하지 않도록 신경써야한다.

 

 

 

복사 생성자의 호출 시점

- 복사 생성자의 호출 시점은 3가지로 구분된다.

  • 기존에 생성된 객체를 이용해서 새로운 객체를 초기화할 때
SomeClass sc1;
SomeClass sc2 = sc1;
  • Call by value 함수호출 과정에서 객체를 인자로 전달할 때
SomeClass Func(SomeClass sc)
{
    ...
}

void main()
{
    SomeClass sc;
    Func(sc)	// 호출하게 되면 매개변수 sc가 할당되는 동시에 초기화
}
  • 함수에서 객체를 참조형으로 반환하지 않을 때
SomeClass Func(SomeClass sc)
{
    return sc	// 반환할 때 메모리 공간이 할당되면서 동시에 초기화
}

void main()
{
    SomeClass sc1;
    SomeClass sc2 = Func(sc1);
}

  ※ 즉, 위 코드에서 반환되는 sc의 객체는 인수로 받은 sc가 아니라 '임시객체'가 만들어져 이 '임시객체'에서 복사 생성자가 호출되어 return에 명시된 객체가 인자로 전달된다.

 

 

 

임시객체, 소멸시점

- 클래스 외부에서 객체의 멤버함수에 접근하는 방법은 다음 세가지이다.

  • 객체에 붙여진 이름
  • 객체의 참조 값 (임시객체)
  • 객체의 주소 값

- 임시객체가 생성된 위치에는 임시객체의 참조 값이 반환된다.

- 그렇기 때문에 다음과 같은 구성이 가능하다.

#include <iostream>
using namespace std;

class Test
{
private:
    int n;
public:
    Test(int n)
    {
        cout << "Create" << endl;
        this->n = n;
    }
    void Show()
    {
        cout << n << endl;
    }
    ~Test()
    {
    	cout << "Destroy" << endl;
    }
};

void main()
{
    Test(100).Show();
    cout << "-----" << endl;
    const Test& t = Test(200);
    cout << "-----" << endl;
    
    //결과
    //Create
    //100
    //Destroy
    //-----
    //Create
    //-----
    //Destroy
}
  • 참조자는 '임시객체'에 대한 참조가 가능하기 때문에 위와 같이 사용이 가능하다.
  • 이 임시객체는 반환된 뒤 다음 줄로 넘어가면 자동으로 소멸 되지만, '임시객체'에 대한 참조자가 존재하면 바로 소멸되지 않는다.

※ 복사 생성자가 일어나지 않는 예외

SomeClass Func()
{
    return SomeClass
}

void main()
{
    SomeClass sc = Func();
}
  • 위의 코드에서 sc 객체를 생성해서, Func()에서 반환되는 객체를 가지고 대입연산을 진행하는것으로 이해할수도 있지만 위와 같은 상황에서는 객체를 생성하지 않고 반환되는 임시객체에 sc라는 이름을 할당한다고 보면 된다. (객체의 생성 수를 하나 줄여서 효율성을 높이기 위해서이다.)
반응형

'Stack > C++' 카테고리의 다른 글

C++ 함수 오버로딩, Deault 매개변수  (0) 2021.10.24
C++ this 포인터  (0) 2021.10.24
C++ 파일 입출력 ofstream, ifstream  (0) 2021.10.16
C++ 생성자, 복사생성자, 소멸자 (+ const)  (0) 2021.10.15
C++ 동적할당 new, delete  (0) 2021.10.13
반응형

 

※ C의 파일 입출력은 다음 링크에서 확인

 

C 파일 입출력

파일 입출력 - 프로그램 내의 정보를 외부 파일에 저장하거나 외부 파일의 정보를 프로그램으로 불러오는 방식. ※ 스트림 : 구현한 프로그램과 참조할 데이터가 저장되어 있는 파일 사이에 놓

srdeveloper.tistory.com


 

파일 입출력

- 프로그램 내의 정보를 외부 파일에 저장하거나 외부 파일의 정보를 프로그램으로 불러오는 방식

- 필요 헤더 : <fstream>

- 파일 내용 출력 : << 내용

- 파일 내용 입력 : >> 내용

 

 

 

ofstream

- 쓰기모드 형태로 파일 정보를 담는다.

- 파일이 없을경우 파일을 생성한다.

- ofstream.save(FileName, OpenMode)

  • OpenMode : default값은 덮어쓰기 모드이며, 파일 내용을 덧붙이려면 ios::app를 입력한다.

- ofstream.close()

  • 스트림을 해제하는 함수.
#include <fstream>
using namespace std;

void main()
{
    ofstream f;
    f.open("Temp.txt");
    if(f.is_open())
    {
        f << "Empty" << endl;
        f.close();
    }
}

 

 

 

 

ifstream

- 읽기모드 형태로 파일정보를 담는다.

- 파일이 없을경우 NULL을 반환한다.

- >>

  • 띄어쓰기 또는 개행단위로 문자열을 가져온다.

- getline(ifstream, string)

  • 개행단위로 문자열을 가져온다.
  • 필요 헤더 : <string>
#include <fstream>
#include <string>
using namespace std;

void main()
{
    ifstream f;
    string str;
    f.open("Temp.txt");
    
    //1. >> 연산자
    while(!f.eof())
    {
        f >> str;
    }
    
    //2. getline()
    while(!f.eof())
    {
        getline(f, str);
    }
}
반응형

'Stack > C++' 카테고리의 다른 글

C++ this 포인터  (0) 2021.10.24
C++ 복사 생성자 심화  (0) 2021.10.17
C++ 생성자, 복사생성자, 소멸자 (+ const)  (0) 2021.10.15
C++ 동적할당 new, delete  (0) 2021.10.13
C++ 참조자(Reference)  (0) 2021.09.29
반응형

 

들어가기에 앞서...

const

- const 변수 : 해당 변수를 정보 변경이 불가능한 상수로 변환.

- const 함수 : 해당 함수에서 const의 위치에 따라 정보의 변환을 막거나 반환값을 상수로 바꾼다.

1. const 변수

void main()
{
    const int i = 10;
    i = 20;	//에러 발생
}
  • 선언 하는 순간의 초기화 값 이외에 다른 값을 대입하려하면 에러가 발생한다.

 

2. const 함수

class ConstClass
{
private:
    int iMember;
public:
    ConstClass() { }
    void SetNum(int i) const
    {
        iMember = i;	//에러발생
    }
};
  • 함수의 뒤에 const가 붙으면 해당 함수의 블럭에서 값의 변경이 불가능하다.
class ConstClass
{
private:
    int iMember;
public:
    ConstClass() { }
    const int* GetNum()
    {
        return &iMember;
    }
};

void main()
{
    ConstClass constClass;
    *(constClass.GetNum()) = 100;	//에러발생
}
  • 함수의 반환형 앞에 const가 붙으면 반환한 값에 대한 변경이 불가능하다.

 

 

 

생성자

- 클래스 객체가 만들어질때 자동으로 단 한번 호출되는 함수

- 반환값이 없고, 클래스명과 동일한 이름으로 함수를 만든다.

- 객체의 멤버변수를 초기화하는 목적으로 사용된다.

- 생성자도 함수의 일종이기 때문에 오버로딩이 가능하다.

- 매개변수에 default값을 설정할 수 있다.

#include <iostream>
using namespace std;

class Test
{
private:
    int aMember, bMember;
public:
    Test()
    {
        aMember = 5;
        bMember = 10;
    }
    Test(int a, int b)
    {
        aMember = a;
        bMember = b;
    }
    int GetA() { return aMember; }
    int GetB() { return bMember; }
};

void main()
{
    Test t;
    cout << "Test.a : " << t.GetA() << ", Test.b : " << t.GetB() << endl;
    
    //결과 : Test.a : 5, Test.b : 10
    
    Test t2(20, 30);
    cout << "Test.a : " << t2.GetA() << ", Test.b : " << t2.GetB() << endl;
    
    //결과 : Test.a : 20, Test.b : 30
}

 

※ 생성자를 호출할 때 주의할 점

- 생성자는 다음과 같이 호출할 수 있다.

  • Class Class
  • Class* ptrClass = new Class;
  • Class* ptrClass = new Class();

- 다음과 같은 생성자는 호출할 수 없다. (컴파일 에러가 발생한다.)

  • Class Class()

Why?

- Class Class()를 생성자의 호출 문으로 인정해 버리면, 컴파일러는 이러한 문장을 만났을 때, 이것이 객체생성문인지 함수호출문인지 구분할 수 없게되기 때문에 이러한 유형의 문장은 함수 호출에만 사용하기로 약속되어있다.

 

 

 

복사 생성자

- 동일한 클래스형의 다른 객체의 정보를 복사하여 새로운 객체를 만든다.

- 일반 변수를 초기화 할 때 다른 변수의 값을 이용하는 경우와 같다.

class Test
{
private:
    int iMember;
public:
    Test(int i)
    {
        iMember = i;
    }
    Test(Test& t)
    {
        iMember = t.iMember;
    }
    int GetNum() { return iMember; }
};

void main()
{
    Test t1(20);
    Test t2(t1);
    cout << t1.GetNum() << endl;
    cout << t2.GetNum() << endl;
    
    //결과
    //20
    //20
}

 

※ 디폴트 복사 생성자

- 복사생성자는 정의하지 않아도, 멤버대 멤버의 복사를 진행하는 디폴트 복사 생성자가 자동으로 삽입된다.

class Test
{
private:
    int iMember;
public:
    Test(int i)
    {
        iMember = i;
    }
};

void main()
{
    Test t1(20);
    Test t2(t1);
}
  • Test 클래스에 복사생성자를 정의하지 않아도t2(t1)이 문제없이 컴파일된다.
  • Test t2 = t1;으로 초기화를 시도해도 묵시적 변환으로 인해Test t2(t1);으로 변환되어서 객체가 생성된다.

- 묵시적 변환으로 인해 복사 생성자가 호출되는것을 막으려면 복사 생성자 앞에 explicit 키워드를 붙이면 대입 연산자를 이용한 객체의 생성 및 초기화는 불가능해진다.

  ※ 묵시적 변환은 복사 생성자에서만 일어나는것이 아니라 전달인자가 하나인 생성자가 있다면, 이 역시 묵시적 변환이 발생한다.

 

 

 

콜론 초기화 (멤버 이니셜라이저)

- 해당 생성자의 몸체보다 먼저 매개변수를 받아 초기화하는 방법

- 클래스 멤버변수 중에서 변수 선언과 동시에 초기화 해야하는 변수(ex. const)에 사용

class Test
{
private:
    const int iMember;
public:
    Test(int i) : iMember(i) { }
}
  • const로 선언한 iMember의 값을 생성자의 몸체에서 초기화하게되면 에러가 발생하지만 멤버 이니셜라이저를 사용하게 되면 const로 선언한 멤버의 초기화가 가능하다.
  • 좀 더 쉽게 설명하자면 다음과 같다.
//클래스에서 멤버 이니셜라이저를 사용했을때.
const int i = 20;
//클래스의 생성자 몸체에서 초기화 했을때.
const int n;
n = 20;

※ 멤버 이니셜라이저를 사용하는 것이 성능상 이점이 있다고는 하나, 요즘같이 하드웨어의 성능이 좋은 시대에서는 큰 의미를 가지지 않는다.

 

 

 

소멸자

- 클래스 객체가 소멸할 때 자동으로 호출되는 함수

- 클래스의 이름 앞에 '~'가 붙는다.

- 매개변수는 void형으로 선언되어야 하기 때문에, 오버로딩과 디폴트 값 설정이 불가능하다.

- 생성자와 마찬가지로 반환값이 없다.

- 객체의 동적할당된 멤버변수를 할당해제하는 목적으로 사용된다.

#include <iostream>
using namespace std;

class Test
{
private:
    int* iMember;
public:
    Test()
    {
        iMember* = new int(20);
    }
    ~Test()
    {
    	cout << "소멸자 호출" << endl;
        delete iMember;
    }
    void Display()
    {
        cout << *iMember << endl;
    }
};

void main()
{
    Test t;
    t.Display();
}

//결과
//20
//소멸자 호출
반응형

'Stack > C++' 카테고리의 다른 글

C++ 복사 생성자 심화  (0) 2021.10.17
C++ 파일 입출력 ofstream, ifstream  (0) 2021.10.16
C++ 동적할당 new, delete  (0) 2021.10.13
C++ 참조자(Reference)  (0) 2021.09.29
C++ 클래스, 객체, 인스턴스  (0) 2021.09.29
반응형

 

new

 - Heap 영역에 동적으로 공간을 할당해주는 연산자.

 - 사용 예시 : new Type

void main()
{	
    int* iPtr = new int;
}
  • new 연산자를 쓴 뒤 할당할 자료형을 입력하면 Heap영역에서 동적할당을 하고 시작주소를 반환받는다.
  • C의 (int*)malloc(sizeof(int))와 같다.

 

 

 

delete

 - Heap 영역에 할당된 공간을 해제하는 연산자

 - 사용 예시 : delete var*

void main()
{
    int* iPtr = new int;
    delete iPtr;
}
  • delete 연산자를 쓴 뒤 포인터 변수를 입력하면 동적할당한 공간을 반환한다.
  • C의 free()와 같다.
  • 동적배열의 경우엔 delete명령어 뒤에 []를 붙여서 사용한다.
반응형

'Stack > C++' 카테고리의 다른 글

C++ 파일 입출력 ofstream, ifstream  (0) 2021.10.16
C++ 생성자, 복사생성자, 소멸자 (+ const)  (0) 2021.10.15
C++ 참조자(Reference)  (0) 2021.09.29
C++ 클래스, 객체, 인스턴스  (0) 2021.09.29
C++ 객체지향  (0) 2021.09.28

+ Recent posts