Developer

6.(C++) 구조체 본문

Programming Language/C++

6.(C++) 구조체

DPhater 2020. 8. 1. 22:44

구조체 변수 선언

#include<iostream>
#include<string>

using namespace std;

struct student{
	string name;
	int id;
	int age;
	string phonenumber;
};

int main(){
	student a1={"김모군",123456,20,"010xxxxxxxx"};
	cout<<a1.name<<" "<<a1.id<<" "<<a1.age<<" "<<a1.phonenumber<<endl;
	return 0;	
}

코드1 실행 결과

C++의 경우 사용자 정의 타입도 기본 타입과 같이 관리하기 때문에 C에서 구조체 변수를 선언할 때 처럼 struct studeant a1;과 같이 구조체를 사용한다고 작성해줄 필요가 없다. typedef를 사용하지 않아도 구조체 변수를 편하게 선언할 수 있는 것이다. 물론 typedef를 사용해도 정상적으로 작동한다. 구조체를 사용할 경우 C와의 호환을 위해서는 typedef를 사용해 주는것이 좋다.

멤버 함수

C언어와의 차이는 바로 멤버 함수 이다. C++에서는 구조체 멤버로 변수뿐만 아니라 함수도 가질 수 있다.

#include<iostream>
#include<string>

using namespace std;

struct student{
	string name;
	int id;
	int age;
	string phonenumber;
	
	void print(){
		cout<<name<<" "<<id<<" "<<age<<" "<<phonenumber<<endl;	
	}
};

int main(){
	student a1={"김모군",123456,20,"010xxxxxxxx"};
	student a2={"이모군",234567,21,"011xxxxxxxx"};
	a1.print();
	a2.print();
	return 0;	
}

코드2 실행 결과

구조체 student의 멤버로 print()함수가 정의되어 있다. 보통 멤버 변수를 Field, 멤버 함수를 메서드(Method)라고 부른다. 메서드의 경우 해당 구조체의 고유의 동작을 나타낼 때 유용하다. 이렇게 코드를 작성한 경우 해당 구조체를 다른 프로젝트에 사용할 때 옮기기가 편하다.

#include<iostream>
#include<string>

using namespace std;

struct student{
	string name;
	int id;
	int age;
	string phonenumber;
	
	void print();
};

void student::print(){
		cout<<name<<" "<<id<<" "<<age<<" "<<phonenumber<<endl;	
}

int main(){
	student a1={"김모군",123456,20,"010xxxxxxxx"};
	student a2={"이모군",234567,21,"011xxxxxxxx"};
	a1.print();
	a2.print();
	return 0;	
}

코드3 처럼 구조체 내부에는 구조체 멤버 함수의 원형만 선언해주고, 외부에서 해당 함수를 작성해 줄 수 있다. 외부에서 멤버함수를 정의해주려면 반환타입과 함수 이름사이에 "구조체이름" "::"연산자를 작성해 어떤 구조체의 함수를 정의하는 것인지 작성해 주어야한다.

코드2와 코드3의 동작은 똑같으나 내부에 정의하면 inline속성을 가지게된다(inline속성은 이전 글에서 배웠다). 반대로 외부에 정의하게 된다면 inline속성을 가지지 않는 함수가된다. 물론 외부에 작성할 때 inline키워드를 작성해주면 외부에 작성해도 inline속성을 가지게 할 수 있지만 이 방법의 경우 inline여부를 컴파일러가 결정하기 때문에 무조건 inline속성을 가진다고 장담할 수 없다.

접근 지정자

C++은 접근 지정자를 통해 외부에서의 멤버 참조를 통제할 수 있다. 접근 지정자의 경우 다음 3가지가 있다.

private : 내부에서만 사용 가능(공개되지 않음)

public : 누구나 사용 가능 (인터페이스 역할)

protected : 내부와 상속된 자식에서만 접근 가능(클래스 배울 때 사용할 예정)

구조체의 default접근 지정자는 public이다. 따라서 a1.name="기기기" 와 같이 임의로 멤버변수를 변경할 수 있다. 물론 이름의 경우 바뀔 수 있다. 하지만 나이를 살펴보자 누군가 a1.age=8888과 같이 말도안되는 값을 작성해도 우리는 막을 방법이 없다. age라는 멤버변수가 public속성이어서 누구든지 접근가능 하기 때문이다. 그럼 코드를 수정해보자.

#include<iostream>
#include<string>

using namespace std;

struct student{
private:
	string name;
	int id;
	int age;
	string phonenumber;
public:
	void print(){
		cout<<name<<" "<<id<<" "<<age<<" "<<phonenumber<<endl;	
	}
	void setname(string aname){
		name=aname;
	}
	void setid(int aid){
		id=aid;
	}
	void setage(int aage){
		if(aage<=100)
			age=aage;
	}
	void setphonenumber(string aphonenumber){
		phonenumber=aphonenumber;
	}
};


int main(){
	student a1;
	a1.setid(123456);
	a1.setname("김모군");
	a1.setage(21);
	a1.setphonenumber("010xxxxxxxx");
	a1.print();
}

코드4 실행 결과

멤버 변수들은 private블록에 선언해 외부에서 사용이 불가능하다. 임의로 변경이 불가능 하다는 것이다. 하지만 이렇게 숨겨만 놓으면 값을 설정할 수 없기때문에 외부에서 통제된 조건으로 멤버 변수를 설정할 수 있는 함수들을 작성해 주었다. 이러한 함수를 보통 액세서(Accessor)라고 한다.

setage()함수를 살펴보자. 코드3에서는 a1.age=333과 같이 직접 멤버변수를 사용해 변경할 수 있었고, 이러한 잘못된 값을 통제할 수 도 없었다. 하지만 코드4의 경우 멤버 변수가 private블록에 선언되어 있어 a1.age처럼 직접 멤버 변수를 참조할 수 없다. 액세서를 사용해 설정해야 하는데 이 경우 조건을 주어 잘못된 값일 경우 수행이 안되도록 통제를 할 수 있다.

아래의 두 사진을 보고 접근지정자를 사용했을 때와 안했을 때의 차이를 살펴보자.

접근지정자 사용 안했을 때

위의 사진은 접근지정자를 사용하지 않았을 때 구조체 변수 a1에서 사용할 수 있는 목록을 나타낸다. 구조체의 경우 default가 public이므로 모든 멤버 변수와 멤버 함수를 접근할 수 있는걸 알 수 있다.

접근지정자 사용 했을 때

위의 사진은 접근지정자를 사용했을 때 구조체 변수 a1에서 사용할 수 있는 목록을 나타낸다. public블록에 작성된 멤버 함수만 사용 가능한 것을 알 수 있다.

이제 바로 다음에 Class를 알아볼것이다. class라고 특별한 것은 아니다. C++에서 확장된 구조체를 C의 구조체와 비교할 수 있도록 이름을 만든것이다. struct를 class로 바꾸기만 하면 클래스가 되는것이다.

물론 구조체와 클래스 사이에도 차이점은 존재한다. 기본(default) 접근 지정자인데 구조체의 경우 public 이었지만 클래스의 경우 private이다. 더 자세한것은 다음 글에서 알아보자.

'Programming Language > C++' 카테고리의 다른 글

8.(C++) 클래스(2)_생성자,파괴자(소멸자)  (0) 2020.08.01
7.(C++) 클래스 (1)  (0) 2020.08.01
5.(C++) 함수  (0) 2020.08.01
4.(C++) 레퍼런스 (Reference)  (0) 2020.08.01
3.(C++) 제어문  (0) 2020.08.01
Comments