[C++] 클래스(class) 개념 및 선언 (plus. this 포인터)

2022. 6. 30. 00:26♣ C++

 

이번 포스팅에선 클래스에 대해 알아보겠습니다.

클래스: 특정 객체를 선언하기 위해 변수와 메서드를 묶는 일종의 틀. 즉, 변수 + 메서드의 묶음.

 

개발 환경 : VSCode, Windows 10

 

 

 

 

 

기본 개발 세팅은 다음과 같습니다.

#include <iostream>
#include <string.h>
#include <string>
using namespace std;

int main()
{
	return 0;
}

 

 

 

 

 

📌 클래스(class) 정의


 

클래스는 비슷한 성향의 변수와 관련 프로세스를 수행하는 메소드를 정의한 틀입니다.

여러 타입의 데이터와 함수를 저장할 수 있는 구조체의 상위 호환으로 볼 수도 있습니다. 

 

 

클래스에는 멤버 변수(프로퍼티), 멤버 함수(메소드)가 있습니다.

 

 

 

다수의 객체를 생성하는데 쓰이며, 객체 지향 프로그래밍(OOP)에 있어 핵심적인 개념입니다.

당연하게도 OOP의 특성인 (1) 추상화 (2) 캡슐화 (3) 정보 은닉 (4) 상속성 (5) 다형성 등을 구현할 수 있습니다. 

 

* 만약 객체 지향 프로그래밍에 대해 더 알고 싶다면?

=> https://mengu.tistory.com/92?category=942021 

 

 

 

💥 꼭 알아야 하는 개념

 

[개념] 인스턴스(instance)란 무엇인가요?

[답변] 클래스를 사용하기 위해 선언하는 클래스 타입의 객체를 말합니다. 클래스 타입의 변수라고 생각하셔도 무방합니다. 다른 변수와 마찬가지로 메모리에 대입되며, 인스턴스는 자신만의 멤버 변수를 가집니다. 멤버 함수는 같은 클래스 타입의 인스턴스라면 모두 똑같이 공유합니다.

 

 

 

 

 

📌 클래스(class) 선언


 

클래스 선언 양식은 다음과 같습니다.

class 클래스 이름
{
	private(생략가능):
    		멤버변수1의타입 멤버변수1의이름;
        	멤버변수2의타입 멤버변수2의이름;
        	멤버함수1의원형;
        	멤버함수2의원형;

	public(생략불가):
    		멤버변수3의타입 멤버변수3의이름;
        	멤버변수4의타입 멤버변수4의이름;
        	멤버함수3의원형;
        	멤버함수4의원형;

	protected(생략가능):
    		멤버변수5의타입 멤버변수5의이름;
        	멤버변수6의타입 멤버변수6의이름;
        	멤버함수5의원형;
        	멤버함수6의원형;
};

private, public, protected 등의 접근 제어 지시자를 설정하고, 그 안에 멤버 변수와 멤버 함수의 원형을 정의해줍니다. private와 protected 접근 제어 지시자는 생략이 가능하지만, public은 생략할 수 없습니다. 

 

 

간단한 Sports 클래스를 선언해보겠습니다.

class sports
{
    public:
        string tennis = "테니스";
        void ilike(string);
};

tennis라는 string 멤버 변수와 ilike라는 멤버 함수 원형을 정의했습니다. 멤버 함수는 클래스 안에서도 정의할 수 있지만, 코드가 길어지면 복잡할 수 있으므로 클래스 선언 밖에서 정의해줍니다.

 

 

🎨 멤버 함수 정의

반환타입 클래스::멤버함수이름(변수){몸체;};

void sports::ilike(string s)
{
	cout << "나는 " << s << "와 " << tennis << " 종목을 좋아합니다." << endl;
}

멤버 함수를 정의했습니다. 그렇다면 이제 main() 함수 안에서 인스턴스를 생성해줍니다.

 

 

🎨 인스턴스 생성 및 활용

클래스 인스턴스이름;
인스턴스이름.멤버함수();


sports tennis;
tennis.ilike(인수);

인스턴스를 선언하는 방법은 간단합니다. 다른 변수들이 타입 변수이름; 으로 선언하듯이 class이름 인스턴스이름;으로 선언합니다.

 

 

전체 코드입니다.

#include <iostream>
#include <string.h>
#include <string>
using namespace std;


class sports
{
    public:
        string tennis = "테니스";
        void ilike(string);
};

// main() 함수 본문
int main()
{   
    string s = "농구";
    sports tennis;
    tennis.ilike(s);
} 

void sports::ilike(string s)
{
	cout << "나는 " << s << "와 " << tennis << " 종목을 좋아합니다." << endl;
}

 

결과

나는 농구와 테니스 종목을 좋아합니다.

 

 

 

 

 

 

📌 클래스(class)의 접근 제어 지시자


 

클래스는 OOP의 특성 중 하나인 정보 은닉을 구현합니다.

구조체는 외부에서 접근이 가능합니다. 하지만 클래스는 특정 변수와 함수에 대해선 외부 접근이 불가능하도록 할 수 있습니다. public, private, protected를 통해 접근을 제안합니다.

 

 

public 접근 제어 지시자

: 외부에 공개되고, 어디서나 접근 가능합니다. private 멤버와 프로그램 사이의 인터페이스 역할을 맡기도 합니다. public 멤버 함수를 통해서는 private 멤버에도 접근이 가능합니다.

 

private:
        string secret = "사실 난 나달을 좋아해";
        void iintroduce(string);
        
        
void sports::iintroduce(string secret){cout << secret;}

private 접근 제어 지시자를 사용한 후, 멤버 변수와 멤버 함수를 정의했습니다. 

 

 

외부에서 만약 private의 멤버 함수를 사용하면 다음과 같은 오류를 전달합니다.

"함수 \"sports::iintroduce\" (선언됨 줄 33)에 액세스할 수 없습니다."

 

 

 

private 접근 제어 지시자

: 외부에 공개되지 않습니다. public 멤버 함수를 통해서만 접근 가능합니다. 생략 가능하며, 세부적인 동작을 구현하는 데 사용됩니다.

 

class sports
{
    private:
        string secret = "사실 난 나달을 좋아해";
        void iintroduce(string);

    public:
        string tennis = "테니스";
        void ilike(string);
};


void sports::ilike(string s)
{
	cout << "나는 " << s << "와 " << tennis << " 종목을 좋아합니다." << endl;
    iintroduce(secret);
}

void sports::iintroduce(string secret){cout << secret;}

public에서 ilike멤버 함수와 tennis 멤버 변수를 정의했습니다.

ilike 멤버 함수에선 private의 멤버 변수와 멤버 함수에 접근할 수 있습니다. ilike 멤버 함수에서 iintroduce 멤버 함수를 호출하도록 정의했습니다. 

 

 

다음은 private, public 접근 제어 지시자 예시를 보여주는 코드입니다.

#include <iostream>
#include <string.h>
#include <string>
using namespace std;


class sports
{
    private:
        string secret = "사실 난 나달을 좋아해";
        void iintroduce(string);

    public:
        string tennis = "테니스";
        void ilike(string);
};

// main() 함수 본문
int main()
{   
    string s = "농구";
    sports tennis;
    tennis.ilike(s);
} 


void sports::ilike(string s)
{
	cout << "나는 " << s << "와 " << tennis << " 종목을 좋아합니다." << endl;
    iintroduce(secret);
}

void sports::iintroduce(string secret){cout << secret;}

 

결과

나는 농구와 테니스 종목을 좋아합니다.
사실 난 나달을 좋아해

 

 

 

protected 접근 제어 지시자

: 파생 클래스와 관련된 접근 제어 지시자입니다. 파생 클래스에 대해선 public 멤버처럼 취급하지만 외부에 대해선 private 멤버로 취급합니다. 이에 대한 내용은 파생 클래스 포스팅에서 자세히 다루겠습니다.

 

 

 

 

 

 

📌 this 포인터


 

같은 클래스끼리는 멤버 함수를 공유합니다. 만약 자기 자신을 함수의 인수로 넣고 싶을 때는 어떻게 해야 할까요?

인스턴스는 자기 자신만의 this 포인터를 가집니다. 해당 멤버 함수를 호출한 객체를 가리키며, 정확한 파악이 가능합니다.

 

 

간단한 운동 선수 클래스를 만들어서 예시를 보여드리겠습니다.

자기 자신을 인수로 넣을 땐 다음과 같이 코드를 입력합니다.

// 클래스 선언
class player
{
    public:
        player(const string& name, int height);
        string name_;
        int height_;
        const player& lover(const player&);
};

return 타입을 const 클래스이름&로 입력합니다. 인수도 const 클래스이름&로 입력합니다.

 

 

다음은 함수 정의입니다.

// 함수 정의
player::player(const string& name, int height)
{
    name_ = name;
    height_ = height;
}

const player& player::lover(const player& player)
{
    if (this->height_ > player.height_){
        return *this;
    }
    else{
        return player;
    }
}

첫 번째 함수는 클래스 선언 시 필요한 매개 변수를 받는 함수입니다.

두 번째 함수는 클래스를 인수로 받아서 서로의 멤버 변수를 비교한 후, 더 큰 객체를 반환하는 함수입니다.

자기 자신을 인수로 넣는다면 this->멤버 변수로 넣습니다.

자기 자신을 반환하고 싶다면 *this로 반환합니다.

 

 

전체 코드입니다.

#include <iostream>
#include <string.h>
#include <string>
using namespace std;


class player
{
    public:
        player(const string& name, int height);
        string name_;
        int height_;
        const player& lover(const player&);
};

// main() 함수 본문
int main()
{   
    player nadal("nadal", 182);
    player federer("federer", 184);
    cout << "나는 nadal과 federer 중 " << nadal.lover(federer).name_ << " 을 더 좋아해." << endl; 

} 

player::player(const string& name, int height)
{
    name_ = name;
    height_ = height;
}

const player& player::lover(const player& player)
{
    if (this->height_ > player.height_){
        return *this;
    }
    else{
        return player;
    }
}

 

 

결과

나는 나달과 페더러 중 federer 을 더 좋아해.

 

 

 

 

💥 주의해야 할 점

[주의 1] 클래스, 구조체 또는 열거체 타입의 비정적 멤버 함수에만 사용 가능합니다.

[주의 2] this 포인터는 포인터 상수입니다. 재할당이 불가능합니다.

 

 

 

 

지금까지 클래스에 대해 알아보았습니다.

수고하셨습니다.