C++

[C++] MyString 클래스 실습

mintuchel 2023. 4. 13. 22:42

 

1. 포인터 받을때 nullptr 항상 체크해주기

2. int 같은거 받을때 0 항상 체크

 

3. 왜 getLength(const char* in) 은 static인지 이유 알기

 

int MyString::getLength(const char* in) {
	if (in == nullptr) return 0; // important
	int ret = 0;
	while (*in++ != NULL)  ret++;
	return ret;
}

 

getLength 함수는 해당 클래스 내 멤버변수를 참조하여 사용하진 않지만

해당 클래스 객체가 사용할 목적으로 정의한 함수이다.

따라서 static으로 클래스 내부에 넣어두는게 좋다

 

왜냐하면 만약 static이 아니면 이 함수 하나 호출하기 위해

불필요한 객체를 생성해야하기 때문이다! (???? 솔까 ㅈㄴ 이상함 이게 이유가 말이 안됨)

 

 

4. 왜 operator << 는 friend 인지 알아놓기

5. 왜 append는 참조형 반환이 안되는지 알아놓기

 

	const MyString& operator+(const MyString& in) { // 이건 reference 붙이면 안됨 이유는?
		// reference로 넘기면 안되는 이유는
		// 이 함수가 끝나면 
		MyString out = *this;
		out.append(in);
		return out;
		// 이 로컬변수 out은 해제되기 때문임!

		// 만약 reference로 넘기고 싶으면
		// MyString* out = new MyString(*this);
		// out->append(int);
		// return *out;
		// 이렇게 포인터로 외부변수로 해줘야함!

		// 여기서는 그냥 reference로 안넘기는 방법을 제시
		// const MyString 이렇게 reference로 넘기지 말자
	}

 

6. 동적할당이면 무조건 복사생성자 직접 정의 ( 얕은 복사로 안되기 때문 )

직접 정의해줘 깊은 복사 하게 만들어야함!

7. 언제 operator를 멤버함수로 해야하는지 외부함수로 해야하는지 알기

8. const 선언 이해

ostream& operator<<(ostream& os, const MyString& in) {
	
	if (in.m_pStr==nullptr || in.getLength() == 0) return os; // const 선언이면 함수사용은 노빠꾸로 제한함
	// const는 data type 선언할때, 함수 선언, 참조자 선언할때 쓰임
	// const 함수는 변하지 않게 한다는것
	// 그래서 const 함수에서 const 변수를 부르는건 안전하다
	// 만약 getLength()에 const가 없으면 에러가 난다

	os << in.m_pStr;
	return os;
}

 

9. 대입연산자 자기자신 받을떄 예외처리 ㅈㄴ 중요

const MyString& MyString::operator=(const MyString& in) {
	// 같은 놈인지 확인 이거 중요 a=a이면 아래 코드 진행하면 a 데이터만 다 날라가는 ㅈ되는 상황
	if (this == &in) {
		return *this;
	}
	releaseMemory();
	m_length = in.getLength(); // length 받고
	if (m_length == 0) return *this;
	assignMemory(); // 초기화
}

 


[MyString.h]

 

#ifndef __MYSTRING_H__
#define __MYSTRING_H__

#include <iostream>

class MyString
{
private:
	char* m_pStr;
	int m_length;

public:
	MyString();
	MyString(const char* in);				
	MyString(const MyString& in);	// copy constructor (복사생성자)
	~MyString(); // destructor (소멸자)

	void assignMemory();
	void releaseMemory();


	int getLength() const {return m_length; }
	static int getLength(const char* in, int max_length=255);


	// cout<< overload
	// 내 객체가 오른쪽에 와야하니까 전역함수로 구현하고 friend 선언
	// const는 상수로 받는다는 것 왜? 바꿀 이유가 없으니
	friend std::ostream& operator<<(std::ostream& o, MyString& in);
	
 
	// 대입연산자 assignment operator
	// 항상 왼쪽은 우리꺼 오른쪽은 MyString 타입
	// 클래스 내 멤버함수로 정의해도 가능
	const MyString & operator=(const MyString& in);
    
	const MyString operator+(const MyString& in);
	void append(const MyString& in);
};

#endif

 


[MyString.c]

 

#include "MyString.h"


MyString::MyString()
{
	m_pStr = nullptr;
	m_length = 0;
}

MyString::MyString(const char* in)
{
	m_length = getLength(in);
	m_pStr = nullptr;
	if (m_length == 0) return;

	assignMevd5mory();

	for (int i = 0; i < m_length; i++)
		m_pStr[i] = in[i];
	m_pStr[m_length] = '\0';

}

MyString::MyString(const MyString& in)
{
/*
	m_pStr = nullptr;
	m_length = 0;
	*this = in;
*/ 

	m_pStr = nullptr;
	m_length = in.getLength();
	if (m_length == 0) return;

	assignMemory();

	for (int i = 0; i < m_length; i++)
		m_pStr[i] = in.m_pStr[i];
	m_pStr[m_length] = '\0';

}

// a = a
const MyString& MyString::operator=(const MyString& in)
{
	if (this == &in) return *this;
	
	releaseMemory();

	m_length = in.getLength();
	if (m_length == 0) return *this;

	m_pStr = new char[m_length + 1];
	for (int i = 0; i < m_length; i++)
		m_pStr[i] = in.m_pStr[i];
	m_pStr[m_length] = '\0';
	
	return *this;

}


MyString::~MyString()
{
	releaseMemory();
}

void MyString::assignMemory()
{
	if (m_length == 0) return;
	m_pStr = new char[m_length + 1];
}

void MyString::releaseMemory()
{
	if (m_pStr != nullptr)
		delete[] m_pStr;
	m_pStr = nullptr;
	m_length = 0;
}

int MyString::getLength(const char* in, int max_length)
{
	if (in == nullptr) return 0;

	int leng = 0;
	while (true)
	{
		if (in[leng] == '\0') return leng;
		if (leng >= max_length) return leng;
		leng++;
	}
}

std::ostream& operator<<(std::ostream& o, MyString& in)
{
	if (in.m_pStr == nullptr || in.getLength() == 0) return o;
	o << in.m_pStr;
	return o;
}

void MyString::append(const MyString& in)
{
	if (in.getLength() == 0) return;
	MyString temp = *this;
	
	if (m_length > 0) releaseMemory();
	m_length = temp.getLength() + in.getLength();
	assignMemory();

	for (int i = 0; i < temp.m_length; i++)
		m_pStr[i] = temp.m_pStr[i];
	for (int i = 0; i < in.m_length; i++)
		m_pStr[i + temp.m_length] = in.m_pStr[i];
	m_pStr[m_length] = '\0';
}

const MyString MyString::operator+(const MyString& in)
{
	MyString out(*this);
	out.append(in);
	return out;
}