String Class 를 까보자
왜 필자가 String Class를 까는지는 각 subtitle의 문제점을 직면했기 때문이다.
1. const char * 을 String객체로 알잘딱 해서 type casting 해준다고?
먼저 String Class를 구현해 보았다.(사실 윤성우 열혈 C++ 에서 가져옴)
// StringClass.cpp
#include <iostream>
#include <cstring>
using namespace std;
class String
{
private:
int len;
char * str;
public:
String();
String(const char * s);
String(const String& s);
~String();
String& operator= (const String& s);
String& operator+= (const String& s);
bool operator== (const String& s) const;
String operator+ (const String& s);
friend ostream& operator<< (ostream& os, const String& s);
friend istream& operator>> (istream& os, String& s);
};
String::String()
:len(0), str(NULL)
{}
String::String(const char * s)
{
len = strlen(s) + 1;
str = new char[len];
strcpy(str, s);
}
String::String(const String& s)
{
len = s.len;
str = new char[len];
strcpy(str, s.str);
}
String::~String()
{
if (str != NULL)
delete[] str;
}
String& String::operator= (const String& s)
{
if (str != NULL)
delete[] str;
len = s.len;
str = new char[len];
strcpy(str, s.str);
return (*this);
}
String& String::operator+= (const String& s)
{
len += (s.len - 1);
char* tempStr = new char[len];
strcpy(tempStr, str);
strcat(tempStr, s.str);
if (str != NULL)
delete[] str;
str = tempStr;
return (*this);
}
bool String::operator== (const String& s) const
{
return (strcmp(str, s.str) ? false : true);
}
String String::operator+ (const String& s)
{
char* tempStr = new char[len + s.len - 1];
strcpy(tempStr, str);
strcat(tempStr, s.str);
String temp(tempStr);
delete[] tempStr;
return (temp);
}
ostream& operator<< (ostream& os, const String& s)
{
os << s.str;
return (os);
}
istream& operator>> (istream& os, String& s)
{
char str[100];
is >> str;
s = String(str);
return (is);
}
C++
복사
여기서 보면 생성자에서는 오버로딩이 되어져 const char * 형을 받는 것을 볼 수 있다.
하지만 대입 연산자에서는 무조건 인자가 String& 으로 되어있다. 하지만 실제로 써보면
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
string s1 = "This is String Class!";
string s2;
s2 = s1;
cout << s1 << endl;
cout << s2 << endl;
char* c;
strcpy(c, "Hello dcho!");
string s3;
s3 = c;
cout << c << endl;
cout << s3 << endl;
return (0);
}
// result
> ./a.out
This is String Class!
This is String Class!
Hello dcho!
Hello dcho!
C++
복사
위 코드를 보면 s2 대입 연산자에서 string 객체가 들어가는 것은 당연하지만 s1, s3 char* 형이 들어가는 것은 조금 이상해 보인다.
하지만 s1에 대입이 되어지는 literal constant char[]도 어떻게 보면 char* 형 이다. 그리고 s3에 들어가는 것도 char* 형 이다.
뭐지 StringClass를 보고, google형님께도 질문을 해도 답이 나오지 않았지만 jseo님께서 명쾌한 해답을 주셨다.
char* → string 변환
애초에 C++에서 String 클래스는 문자열의 처리를 목적으로 정의된 클래스이기에 C-Style의 문자열은 char* 형이 였다. C++에서는 그것을 알잘딱 해서 String 객체로 type casting을 기본적으로 해준다고 한다!
string → char* 변환
반대로도 그냥 되었으면 좋겠지만 아쉽게도 그렇게 하면 컴파일이 에러를 내뱉는다.
error: assigning to 'char *' from incompatible type 'std::__1::string' (aka
'basic_string<char, char_traits<char>, allocator<char> >')
한마디로 변환할 수 없다! 그 이유는 자동 형변환이 안되기 때문이다.
그래서 string class에서 제공해 주는 것이 c_str() 이 멤버 함수를 지원한다.
이 함수를 이용하면 String 객체에서 char* 형 으로 변환되어 저장이 된다.
2. String 객체에 값을 넣을때 주의 할점
나는 이렇게 썼다.
std::string input;
input = hollys.my_cin(); // 대충 입력 받는 함수
for(size_t i = 0; i < input.size(); i++)
input[i] = toupper(input[i]);
std::cout << input << std::endl; // 잘 됨
C++
복사
jji는 이렇게 사용하려고 했다.
std::string input;
std::string cmd;
input = hollys.my_cin();
for(size_t i = 0; i < input.size(); i++)
cmd[i] = toupper(input[i]);
std::cout << cmd << std::endl; // 하나도 안나옴
C++
복사
알아보니 input에 gta를 넣었을때 toupper도 되었고cmd[0] = 'G', cmd[1] = 'T', cmd[2] = 'A'
정상적으로 잘 나왔다. 하지만 cmd.size() -> 0..
알고보니 배열처럼 막 넣기만 했지 정상적으로 값을 추가를 해주려면 += 를 해주어야 했다.
std::string input;
std::string cmd;
input = hollys.my_cin();
for(size_t i = 0; i < input.size(); i++)
cmd += toupper(input[i]); // 수정사항
std::cout << cmd << std::endl; // 잘 됨
C++
복사
앞으로 주의 하자.