본문 바로가기
프로그래밍 공부흔적/C++

[C++] 객체와 클래스에 대한 이야기 정리

by 뷕뺙쀡 2021. 4. 18.

구조체

-클래스는 c와 c++ 언어를 구분짓는 가장 큰 특징이다
-클래스는 구조체의 확장으로 이해할 수 있다.
-구조체는 다양한 형태의 자료집합을 이용해 정의할 수 있다.

#include <iostream>

struct Monster
{
	double hp;
	double mp;
	char level;
};

int main()
{
	Monster mob1; //구조체 변수 선언
	//구조체의 멤버변수에 접근하기 위해서는 . 연산자를 사용한다
	mob1 = { 67.5,34.2,'c' }; //초기화
	Monster mob2 = mob1; //복사
	mob1.level = 'b';//멤버변수에 접근하여 변경

	return 0;
}

 

클래스

-클래스란 기본적으로 멤버 데이터뿐만 아니라 멤버 함수를 가지는 하나의 구조체이다. 
-클래스는 객체지향 프로그래밍의 기법에서 가장 중심 개념이다.
-클래스형의 변수를 객체 또는 인스턴스라고 한다.

객체

-객체는 자신만의 유일한 특성과 상태(state), 행동(behavior)을 갖는다.
-객체의 상태(state)는 데이터 필드 즉 변수로 표현된다.
-객체의 행동(behavior)은 함수에 의해 정의된다.
-객체의 멤버란 데이터필드와 함수를 의미하며, 이를 멤버변수와 멤버함수라 부른다.
-객체가 생성된 후에는 점 연산자(.)를 사용하여 데이터에 접근하고 함수를 호출한다.
-객체의 멤버함수는 같은 클래스의 모든 객체에 공유되므로 단 하나의 복사본만 생성된다. 그러므로 객체의 실제크기는 크지 않다.
-C++에서 하나의 객체로부터 다른 객체로 내용을 복사하기 위해 대입 연산자(=)를 사용할 수 있다. 기본적으로 한 객체의 각각의 데이터 필드는 다른 객체의 대응 부분으로 복사된다. 

클래스와 객체의 관계

-클래스는 객체가 어떻게 생겨야 하는지를 적어놓은 설계도
-객체는 그 설계도(클래스)를 통해 만들어진 인스턴스(instance)
-클래스에는 멤버변수를 초기화하기 위한 생성자가 있다.

생성자

-클래스에 일반변수처럼 객체를 생성할 때 초기값을 주는 것
-생성자는 1)클래스 자신과 같은 이름을 가지며, 2)반환유형을 가질 수 없고, 3)생성자는 객체가 생성될 때 자동호출되며, 4)생성자도 오버로딩을 적용할 수 있고, 5)접근 지정자가 public:으로 설정되어야 한다.
-프로그래머가 생성자를 만들지 않을 경우 '기본생성자'(default constructor)를 만들어 놓는데 이는 매개변수도 없고 내용도 없으므로 아무 일도 하지 않는다.
-그런데 프로그래머가 매개변수를 갖는 생성자를 만들어주면 컴파일러는 더 이상 기본 생성자를 제공하지 않는다. 즉, 매개 변수가 있는 생성자를 만들어 사용하던 중 매개변수를 갖지 않는 생성자가 필요하다면 이를 직접 정의하고 사용해야 한다.


#include <iostream>
#include <cstring>
using namespace std;

class Profile // 프로그래머 정의 클래스는 첫문자를 대문자로 하는 것이 좋다
{
	public:
		//데이터 필드
		int age;
		char job[100];

		//생성자
		Profile();
		Profile(int age) : age(age) 
			//생성자에 초기화목록(initializer list)을 사용하여 초기화
		{
			strcpy_s(job, "대학생!");
		}
		Profile(double);//생성자의 오버로딩

		//멤버함수
		void printProfile()
		{
			cout << "나이는 " << age << "세에 "
				<< "직업은 " << job << "입니다" << endl;
		}
};

//----생성자----//
Profile::Profile()
{
	age = 20;
	strcpy_s(job, "대학생");
}

Profile::Profile(double a)
{
	age = (int)a;
	strcpy_s(job, "대학생?");
}
//-------------//

int main()
{
	Profile p1;
	Profile p2(23);
	Profile p3(22.156);
	p1.printProfile();
	//출력:나이는 20세에 직업은 대학생입니다
	p2.printProfile();
	//출력:나이는 23세에 직업은 대학생!입니다
	p3.printProfile();
	//출력:나이는 22세에 직업은 대학생?입니다

	return 0;
}

 

클래스의 정의와 구현 분리(파일 분리)

-파일 분리시 클래스 정의부분은 .h파일에 구현 부분은 .cpp파일에 저장(헤더파일 포함해야 함, 범위지정 연산자 ::사용하여 클래스 멤버변수와 멤버함수 구현)하고, main()함수는 또 다른 cpp 파일로 분리한다.

다중 포함 방지

-프로그램 내에서 같은 헤더 파일을 여러번 포함(include)시켜 컴파일 오류가 나는 경우가 발생하는데 다중포함을 방지하기 위해서는 #ifdef와 함께 #define 지시자를 사용한다. 이를 inclusion guard라고 하고 이를 헤더파일에 추가해야 다중 포함을 방지할 수 있다.

익명객체

-종종 객체를 생성하고 단지 한 번만 객체를 사용하는 경우가 있다. 이 경우에는 객체에 이름을 줄 필요가 없는데, 이와 같은 객체를 익명 객체(anonymous object)라고 한다.

Profile p1 = Profile();
//인수 없는 생성자를 사용하여 익명 객체 생성
Profile p2 = Profile(21);
//인수 있는 생성자를 사용하여 익명 객체 생성

클래스에서 인라인 함수

-인라인 함수란 함수의 내용이 함수호출 부분에 그대로 옮겨지는 것이다.
-이는 실행의 흐름이 넘어갔다 돌아오거나 인자를 복사하는 과정에서 생기는 시간을 줄여준다.
-함수가 클래스 정의 내부에서 구현되는 경우에는 자동적으로 인라인 함수가 되며, 구현 부분에 만들고 싶다면 앞에 inline이라는 키워드를 적어 헤더파일로 옮겨야 한다.
-인라인 함수는 짧을 때만 사용하는 것이 좋다.

변수의 범위

-전역 변수는 모든 함수의 바깥에 선언되고 모든 함수에서 접근이 가능하다. 전역 변수의 범위는 선언에서 시작하여 프로그램의 끝까지 계속된다. 
-지역 변수는 함수 내부에서 정의된다. 지역 변수의 범위는 선언에서 시작하여 변수가 포함된 블록의 끝까지 계속된다. 
-클래스 안에 선언되는 멤버변수는 접근지정자가 private일 때와 public일 때 다르게 동작한다. 
private일 때:클래스 안의 생성자와 함수에서만 접근가능
public일 때: 외부함수에서도 객체생성 후 . 연산자 통해 접근가능
-만약 지역변수가 멤버변수와 같은 이름을 가진다면, 지역 변수가 우선권을 가진다. 하지만 클래스 안에서 같은 이름의 변수는 선언하지 않는 것이 좋다.

데이터 필드 캡슐화

-데이터 필드를 직접 수정할 수 있을 경우 데이터가 임의로 수정될 수 있고 클래스의 유지보수가 어려워진다. 그러므로 데이터 필드를 private으로 선언하고 get 함수와 set 함수를 사용하여 데이터필드에 접속해야하는데 이를 데이터 필드 캡슐화(data field encapsulation)이라고 한다.

//Profile.h
//헤더 파일에는 클래스의 정의 부분

//다중 포함 방지
#ifndef PROFILE_H
#define PROFILE_H

class Profile 
{
	public:
		Profile();
		Profile(int age);
		Profile(double);

		//함수가 클래스의 정의 내부에서 정의된다면, 
		//inline을 붙이지 않아도 저절로 inline 함수이다
		int getAge() { return age;} //inline 함수를 만드는 첫번째 방법
		char* getJob();
		void setAge(int newAge);
		void printProfile();
		
	private:
		int age;
		char job[100];

};
inline char* Profile::getJob()
{
	return job;
}

#endif

/

//Profile.cpp
//클래스의 구현 부분
#include <iostream>
#include <cstring>
#include "Profile.h" //헤더 파일 포함
using namespace std;

Profile::Profile()
{
	age = 20;
	strcpy_s(job, "대학생~");
}

Profile::Profile(int age) : age(age)
{
	strcpy_s(job, "대학생!");
}

Profile::Profile(double a)
{
	age = (int)a;
	strcpy_s(job, "대학생?");
}

void Profile:: printProfile()
{
	cout << "나이는 " << age << "세에 "
		<< "직업은 " << job << "입니다" << endl;
}

void Profile::setAge(int newAge)
{
	age = newAge;
	if (age > 30)
	{
		strcpy_s(job, "직장인");
	}
}

/

//testProfile.cpp
//main 함수 부분
#include <iostream>
#include "Profile.h" //헤더파일 포함
using namespace std;

int main()
{
	Profile p1;
	Profile p2(23);
	Profile p3(22.156);
	p1.printProfile();
	//출력:나이는 20세에 직업은 대학생~입니다
	p2.printProfile();
	//출력:나이는 23세에 직업은 대학생!입니다
	p3.printProfile();
	//출력:나이는 22세에 직업은 대학생?입니다

	Profile p4 = Profile(25); //인수 있는 익명 객체 생성
	p4.printProfile();
	//출력:나이는 25세에 직업은 대학생!입니다
	p4.setAge(30); //private로 선언된 멤버변수를 변경함
	p4.printProfile();
	//출력:나이는 30세에 직업은 대학생!입니다

	return 0;
}

 

'프로그래밍 공부흔적 > C++' 카테고리의 다른 글

[C++] 상속  (0) 2021.06.06
[C++] 연산자 오버로딩  (0) 2021.06.06
[C++] 해시 문제를 풀 때 쓴 vector STL 정리  (0) 2020.12.30
[C++] 배열에 대한 이야기들 정리  (0) 2020.12.02

댓글