C++_OOP5

gimmicks_u·2022년 4월 4일
0

C++

목록 보기
5/5
post-thumbnail

클래스의 동적 메모리 할당

대입 연산자 오버로딩

기호가 같은 연산자를 여러 가지 기능을 가질 수 있도록 정의할 수 있다. 이를 연산자 오버로딩이라고 한다.

#include <iostream>
using namespace std;
class String
{
public:
    String(char ch, int nSize);
    ~String();
    void operator=(const String& s);
    void SetData();

private:
    int nLength;
    char *pBuffer;
};

String::String(char ch, int nSize)
{
    nLength = nSize;
    pBuffer = new char[nLength + 1];
    memset(pBuffer, ch, nLength);
    pBuffer[nLength] = '\0';
    cout << "pBuffer : " << pBuffer << endl;
    cout << "nLength : " << nLength << endl;
}

String::~String()
{
    delete[] pBuffer;
}

void String::operator=(const String& s) // & : CallbyReference하겠다!
{
    delete pBuffer;
    nLength = s.nLength;
    pBuffer = new char[nLength + 1];
    strcpy(pBuffer, s.pBuffer);
}

void String::SetData()
{
    cout << "pBuffer : " << this->pBuffer << endl;
    cout << "nLength : " << this->nLength << endl;
}

int main()
{
    String str1('A', 5);
    String str2('B', 5);
    str1 = str2;
}
pBuffer : AAAAA
nLength : 5
pBuffer : BBBBB
nLength : 5

str1 = str2;
str2.operator=(str1);

두 문장 모두 같은 것이다. 위처럼 본다면 더 직관적으로 이해할 수 있다.

객체의 자기 자신 대입 시에 대한 처리

str1 = str1;

자기 자신을 대입시 먼저 str1이 가르키는 메모리가 delete될것이고, 새로운 메모리 공간을 힙영역에 nLength길이만큼 할당한다. 문제는 strcpy()시에 s.pBuffer값을 가지고 올 수 없으므로 결국 복사는 실패하게 된다.

void String::operator=(const String& s)
{
    if(&s == this)
        return;
    delete pBuffer;
    nLength = s.nLength;
    pBuffer = new char[nLength + 1];
    strcpy(pBuffer, s.pBuffer);
}

operator=()멤버함수에서 전달인자로 넘겨받은 클래스 객체현재 멤버함수의 소속 클래스가 같은지 검사해서 코드는 실행되지 않도록 return 처리하면 문제를 해결할 수 있다.

복사 생성자

String str1('A',3);
String str2 = str1; // 복사 생성자1
String str2(str1); // 복사 생성자2

객체 생성 시 초기화를 하되, 생성되는 객체를 다른 객체로 초기화 할 때 호출되는 생성자.

#include <iostream>
using namespace std;
class String
{
public:
    String(char ch, int nSize);
    ~String();
    String(const String& s);
    void operator=(const String& s);
    void SetData();

private:
    int nLength;
    char *pBuffer;
};

String::String(char ch, int nSize)
{
    nLength = nSize;
    pBuffer = new char[nLength + 1];
    memset(pBuffer, ch, nLength);
    pBuffer[nLength] = '\0';
    // cout << "pBuffer : " << pBuffer << endl;
    // cout << "nLength : " << nLength << endl;
}

String::~String()
{
    delete[] pBuffer;
}

String::String(const String& s)
{
    this->nLength = s.nLength;
    this->pBuffer = new char[this->nLength + 1];
    strcpy(this->pBuffer, s.pBuffer);
}

void String::operator=(const String& s)
{
    if(&s == this)
        return;
    delete pBuffer;
    this->nLength = s.nLength;
    this->pBuffer = new char[this->nLength + 1];
    strcpy(this->pBuffer, s.pBuffer);
}

void String::SetData()
{
    cout << "pBuffer : " << this->pBuffer << endl;
    cout << "nLength : " << this->nLength << endl;
}

int main()
{
    String str1('A', 5);
    String str2(str1);
    // String str2 = str1;  윗문장과 같음
    cout << "대입 후 str2" << endl;
    str2.SetData();
}
대입 후 str2
pBuffer : AAAAA
nLength : 5

operator에서는 pBufferdelete를 해주었지만, 복사생성자에서는 delete를 하지 않는다. 그 이유는 operator에서는 기존에 있던 데이터를 없애고 값을 받아야 했지만, 복사 생성자에서는 객체가 처음 생성되는 시점이기 때문에 delete할 필요가 없기 때문이다.

profile
Done is better than perfect

0개의 댓글