본문 바로가기

C++

[TIL 20장] string함수, explicit, 전방 선언

오늘의 TIL 목차 (22.08. 31)

 

  • string 함수
  • explicit
  • 전방 선언

string 함수


[ string ]

: C++에 들어온 문자열 함수 ( 문자열 끝에 널( '\0' )을 포함하지 않음 )

#include <string> // string 헤더파일 포함

생성 방법
1.
string.str1("Dainn"); // string str1 = "Dainn";
2.
string str2; // 선언 ( 쓰레기값 )
str = "Dainn"; // 초기화

3.
string str3(str2); // 인자값 또는 문자열 넣어 문자열 생성 가능

■ 기능 / 주의

  • string 문자열은 대입 연산자를 통해 대입이 가능하다 ( char 배열은 대입 불가능, 문자열 함수 이용해야 함 )
  • string에 C 배열을 대입할 수 있지만 C 배열에 string 문자열을 대입할 수 없다. ( c_str()함수로 c로 바꿔주면 가능 )
  • string은 '널'을 포함하지 않는다. length() 시 순수 문자열의 길이 출력
@. str.size(); // 문자열 str이 사용하고 있는 사이즈 반환 ( c의 strlen과 유사 ), 널 제외

@. str.length(); // 문자열 str의 길이 반환 ( size() 함수와 유사 ), 널 제외 순수 문자열

@. str.clear(); // 문자열 초기화

@. str.c_str() // C++ string을 C 스타일의 문자열로 변경해주는 함수
- strcpy_s 등 char 배열에 string을 대입하고 싶을 때 사용

[ size와 length의 차이 ]
size는 객체가 메모리에서 실제 사용하고 있는 크기
length는 널 제외 문자열의 길이

string s = "이다인"; // 한글은 한 글자당 2byte
cout << s.size() << "\t" << s.length() << endl; // 6	6
-> 외관상 보기에는 똑같음, 그러나 문자열의 길이를 구한다면 length를 사용할 것

 

■ 예시

string sName = "dainn";
string str("faimly");
char szName[10] = "locco";

//szName = sName;
cout << sName << endl;
	
// 문자열에 char 배열 locco 대입 가능
//string은 대입연산자로 대입 가능 (char 배열은 문자열 함수 이용해야함)
sName = szName; // sName에 locco 대입

cout << szName << endl;

// sName(str); 불가능
sName = str; // sName에 family 대입
	
// C배열에 string대입 불가능, c_str()함수를 이용하여 C언어로 전환 후 가능
strcpy_s(szName, sizeof(sName), sName.c_str());  // locco를 C로 전환 후 szName에 대입

cout << szName << endl;
cout << sName.length() << "\t" << sizeof(szName) << endl; // sName은 family, szName은 loccol;
sName.clear(); // 문자열 초기화
cout << sName << endl; // sName은 초기화됨

출력 결과 :
dainn
locco
family
6 	10
빈칸

 

전방선언


[ 전방선언 ]

: 식별자를 정의하기 전에 식별자의 존재를 컴파일러에게 미리 알리는 방식

#include "Student.h" 대신
class cStudent; 로 사용되는 클래스 명만 선언
  • 헤더파일의 의존성을 회피 ( 헤더파일이 증가할수록 재컴파일 양이 많아져 속도 저하 )
  • 상호 참조가 발생하여 자료형의 크기를 정확히 알 수 없거나 무한루프가 걸리는 문제를 해결하기 위한 문법
    - 소멸자에 소멸자를 호출하면 무한루프에 빠짐 ( 소멸자에 Release()를 넣어주는 이유이기도 함 )

■ 기능 / 주의

  • 전방 선언을 할 경우 그 클래스 관련 객체는 무조건 포인터형으로 선언
    - 컴파일러는 자료형의 종류와 크기를 파악해야 하는데 전방 선언 시 내부가 노출되지 않아 크기를 알 수 없기 때문에
    4byte 크기인 포인터로 객체를 생성하여 크기를 알 수 있도록 할당해줘야 함
  • 전방 선언을 한 .cpp 파일에 꼭 해당 헤더파일을 include, 인스턴스 생성을 위해서 클래스 정보를 알아야 하기 때문
    - 전방 선언은 멤버 함수와 멤버 변수의 유무를 알 수도 호출 할 수도 없음 ( 불필요한 정보를 노출하지 않는다는 장점 }
  • 헤더와 헤더 사이에서 문제가 되는 것이지 .cpp에서는 헤더를 포함해도 상호 참조 문제가 발생하지 않음
  • 전방선언은 상호 참조를 방지하기 위함이니 너무 남발하지 말것
void main(void)
{

 

explicit


[ explicit ]

: 생성자를 통해 암묵적 형 변환(자동 형 변환)이 일어나는 것을 막아주는 기능

 

■ 기능 / 주의

  • explicit는 묵시적 형 변환이 발생하는 생성자 앞에 붙여서 사용한다.
  • 생성자 앞에 explicit 키워드를 붙이면 C 기반의 초기화 ( =을 이용한 초기화 )를 막는다.
class CDainn
{
public:
	CDainn() {} // 1 생성자
	explicit CDainn(int _i) : m_i(_i), m_c(0) {} // 2 생성자
	CDainn(int _i, char _c) : m_i(_i), m_c(_c) {} // 3 생성자

public:
	int m_i;
	char m_c;
};

// CDainn이 들어와야하는데 10이 들어오면 2 생성자를 실행시켜 CDainn으로 묵시적 형변환
// 만약 2생성자가 없었다면 오류 발생 
// 이를 방지하는 것이 묵시적 형변환이 발생하는 2 생성자에 explicit를 붙여주는 것

void Print(CDainn _cd) // 전역 함수
{
	cout << _cd.m_i << ". " << _cd.m_c << endl;
}

void main(void)
{
   Print(10); // CDainn타입을 받는 매개변수에 int를 넘겨줌
    => 10이 묵시적으로 형 변환되어 CDainn의 int를 받는 생성자를 통해 생성된 후 Print() 실행
    => explicit를 붙여 이를 방지함
    
    CDainn cd = 10; // 오류, explicit로 C기반의 초기화를 막음, 원래였음 2 생성자 호출됨
    CDainn cd(10); // explicit로 인해 오직 C++ 기반의 초기화만 허용
}