C++에서 구조체는 클래스의 일종으로 간주되기 때문에, C에서와 달리 구조체 안에 함수를 정의할 수 있다.
/* struct 구조체이름 {
자료형 멤버변수이름;
...
}; */
struct Student {
int number;
char name[10];
double height;
};
// 구조체이름 구조체변수이름
Student vaughan;
Student vaughan2 = {2022, vaughan, 175}; //선언과 동시에 멤버변수 초기화
func()
로 함수 호출 → st.func()
로 함수 호출st.name
→ name
ShowStudentInform()
함수는 구조체 내의 변수에 대한 정보를 출력한다. → 구조체 내에 정의되면서 참조접근이 아니라 직접 접근이 가능해짐 struct Student {
int number;
char name[10];
double height;
//함수 정의
void ShowStudentInform() {
cout<<"학번: "<<number<<endl;
cout<<"이름: "<<name<<endl;
cout<<"키: "<<height<<endl;
}
};
//전역함수로 정의된 경우
void ShowStudentInform(Student st) {
cout<<"학번: "<<st.number<<endl;
cout<<"이름: "<<st.name<<endl;
cout<<"키: "<<st.height<<endl;
}
구조체이름::
struct Student {
int number;
char name[10];
double height;
//함수 원형
void ShowStudentInform();
};
//함수 정의
void Student::ShowStudentInform() {
cout<<"학번: "<<number<<endl;
cout<<"이름: "<<name<<endl;
cout<<"키: "<<height<<endl;
}
inline
을 이용하여 명시적으로 지시해야한다.enum
을 사용한다. struct Student {
//상수 정의
enum {
NAME_LEN = 10,
SHOW = 5
};
int number;
char name[NAME_LEN];
double height;
void ShowStudentInform() { ... }
};
구조체 선언에 사용하는 키워드 struct
를 대신해 class
를 사용하면 클래스를 정의할 수 있다. 그러나 이렇게 정의한 클래스를 선언하면 해당 클래스의 멤버 변수, 함수에 접근할 수 없다!
public
: 어떤 영역에서든 접근이 가능하다.protected
: 상속관계일 때, 유도 클래스에서 접근을 허용한다.private
: 클래스 내에서만 접근이 가능하다.private
접근범위 : number
, name
public
접근범위 : height
, ShowStudentInform()
public
으로 선언된 멤버변수는 구조체의 멤버를 초기화하는 것처럼 초기화할 수 있다. class Student {
private:
int number;
char name[NAME_LEN];
public:
double height;
void ShowStudentInform() { ... }
};
private
로 선언된다.public
으로 선언된다.Student.h
: 클래스의 선언Student.cpp
: 클래스 멤버함수의 정의inline
키워드를 사용해 인라인 함수로 정의한 멤버함수는 클래스의 선언 부분에 해당되기 때문에 헤더파일에 넣어야한다.💡 객체지향 프로그래밍은 현실에 존재하는 사물과 대상, 그리고 그에 따른 행동을 있는 그대로 실체화하여 부품 객체를 먼저 만들고 이것들을 하나씩 조립해 완성된 프로그램을 만드는 기법
//클래스이름 객체이름;
Student vaughan;
//클래스이름* 객체이름 = new 클래스이름;
Student* vaughan = new Student;
💡 멤버 변수에 대해 제한된 방법으로만 접근을 허용하여, 멤버변수가 가질 수 있는 값에 제한을 둘 수 있도록 프로그램을 설계하는 것이 좋다.
public
일 때 발생할 수 있는 문제점InitMembers()
, setX()
, setY()
함수를 선언했다.getX()
, getY()
함수를 선언한다. #include <iostream>
using namespace std;
class Point {
private:
int x;
int y;
public :
int GetX() const;
int GetY() const;
bool InitMembers(int xpos, int ypos);
bool SetX(int xpos);
bool SetY(int ypos);
};
bool Point::InitMembers(int xpos, int ypos) {
if(xpos<0 || ypos<0){
cout<<"잘못된 범위의 값이 전달됨"<<endl;
return false;
}
x = xpos;
y = ypos;
return true;
}
bool Point::SetX(int xpos) {
if(xpos<0){
cout<<"잘못된 범위의 값이 전달됨"<<endl;
return false;
}
x = xpos;
return true;
}
bool Point::SetY(int ypos) {
if(ypos<0){
cout<<"잘못된 범위의 값이 전달됨"<<endl;
return false;
}
y = ypos;
return true;
}
int Point::GetX() const {return x;}
int Point::GetY() const {return y;}
const
선언이 추가되어있는 함수를 의미한다. ex) int GetX() const;
#include <iostream>
using namespace std;
class SneezeCap { public: void Take() const { cout<<"재채기 증상 완화약 처방"<<endl; } }; //재채기 약
class SinivelCap { public: void Take() const { cout<<"콧물 증상 완화약 처방"<<endl; } }; //콧물 약
class SnufflelCap { public: void Take() const { cout<<"코막힘 증상 완화약 처방"<<endl; } }; //코막힘 약
//각 증상을 완화하는 기능을 모아 감기를 낫게하는 목적을 달성하는 하나의 캡슐
class CAP {
private:
//증상 완화를 위한 약 객체
SneezeCap sne;
SinivelCap sin;
SnufflelCap snu;
public:
//약의 복용 절차를 나타내는 복용 함수
void Take() const{
sne.Take();
sin.Take();
snu.Take();
}
};
//감기환자
class ColdPatient {
//감기증상 완화를 위해 캡슐을 처방하는 함수. (캡슐 객체를 인자로 전달받음)
public:
void TakeCAP(CAP &cap) const { cap.Take(); }
};
int main(){
ColdPatient patient;
CAP cap;
patient.TakeCAP(cap);
return 0;
}
객체 생성시 반드시 호출되는 것
클래스명 객체명(생성자인자);
클래스명* 객체명 = new 클래스명(생성자인자);
#include <iostream>
using namespace std;
class Student {
private:
int number;
float grade;
public:
//생성자 정의
Student(){
number = 0;
grade = 0;
}
Student(int num){
number = num;
grade = 0;
}
Student(int num, float g){
number = num;
grade = g;
}
void Show(){
cout<<"학번: "<<number<<endl;
cout<<"학점: "<<grade<<endl<<endl;
}
};
int main(){
Student st1; //기본 생성방법 (==인자가 없는 기본 생성자 1)
Student st2(2021); //생성자 2
Student st3(2022, 4.5); //생성자 3
st1.Show();
st2.Show();
st3.Show();
return 0;
}
Student st1()
으로 객체 생성을 할 수 없는이유💡 멤버 객체의 생성자 호출을 클래스의 생성자 호출과 동시에 진행하여 클래스 객체 생성과 동시에 클래스가 갖는 멤버 객체의 초기화를 가능하게 만들어준다.
: num(n)
의 의미는 int num = n
이다.: upLeft(x1, y1), lowRight(x2, y2)
#include <iostream>
using namespace std;
class Point {
private:
int x;
int y;
public :
Point(const int &xpos, const int &ypos); //생성자
int GetX() const;
int GetY() const;
void SetX(int xpos);
void SetY(int ypos);
};
Point::Point(const int &xpos, const int &ypos) {
x = xpos;
y = ypos;
}
int Point::GetX() const { return x; }
int Point::GetY() const { return y; }
void Point::SetX(int xpos) { x = xpos; }
void Point::SetY(int ypos) { y = ypos; }
class Rectangle {
private:
Point upLeft;
Point lowRight;
public:
Rectangle(const int &x1, const int &y1, const int &x2, const int &y2);
void ShowRec() const;
};
Rectangle::Rectangle(const int &x1, const int &y1, const int &x2, const int &y2)
: upLeft(x1, y1), lowRight(x2, y2) {
}
void Rectangle::ShowRec() const {
cout<<"좌상단: "<<'['<<upLeft.GetX()<<", "<<upLeft.GetY()<<']'<<endl;
cout<<"우하단: "<<'['<<lowRight.GetX()<<", "<<lowRight.GetY()<<']'<<endl;
}
int main(){
Rectangle rec(1, 1, 4, 4);
rec.ShowRec();
return 0;
}
클래스명(){}
클래스명 객체명;
의 방식으로 객체를 생성할 수 없다.private
생성자 #include <iostream>
using namespace std;
class SimpleClass {
private:
int num;
SimpleClass(int n) : num(n) {} //private 생성자
public:
SimpleClass(){}
void SetNum(int i) { num = i; }
SimpleClass& CreateClass(int n) const{
SimpleClass* ptr = new SimpleClass(n);
return *ptr;
}
void Show() const { cout<<"숫자: "<<num<<endl; }
};
int main(){
SimpleClass out;
out.SetNum(100);
SimpleClass in = out.CreateClass(10);
SimpleClass inin = in.CreateClass(1);
out.Show();
in.Show();
inin.Show();
return 0;
}
객체 소멸시 반드시 호출되는 것
~
’가 붙은 형태의 이름을 가진다.delete
를 이용해 할당해둔 메모리 공간을 소멸한다. #include <iostream>
using namespace std;
class Person {
private:
char* name;
int age;
public:
Person(char* str, int n): age(n) {
int len = strlen(str) + 1;
name = new char[len];
strcpy(name, str);
}
void Show() const {
cout<<"나이: "<<age<<endl;
cout<<"이름: "<<name<<endl;
}
//소멸자
~Person() {
delete []name; //동적할당한 멤버를 소멸
cout<<"소멸자 실행됨"<<endl;
}
};
int main(){
Person cls("vaughan", 21);
cls.Show();
return 0;
}
클래스명 배열이름[크기]
클래스명* 배열이름 = new 클래스명[크기];
클래스명() { //body }
형태의 생성자가 정의되어 있어야 한다. #include <iostream>
#include <cstring>
using namespace std;
class Person {
private:
char* name;
int age;
public:
//객체배열 생성을 위한 () 생성자
Person(){
name = NULL;
age = 0;
cout<<"기본 생성자 호출"<<endl;
}
void SetInfo(char* name, int age) {
this->name = name;
this->age = age;
}
void Show() const {
cout<<"이름: "<<name<<endl;
cout<<"나이: "<<age<<endl;
}
};
int main(){
Person arr[3]; //객체 배열
char namestr[10];
int age;
int len;
char* strptr;
//객체 초기화
for(int i=0; i<3 ; i++){
cout<<"이름을 입력하시오: ";
cin>>namestr;
cout<<"나이를 입력하시오: ";
cin>>age;
len = strlen(namestr) + 1;
strptr = new char[len];
strcpy(strptr, namestr);
arr[i].SetInfo(strptr, age);
}
//저장된 객체 배열 출력
for(int i=0; i<3; i++){ arr[i].Show(); }
return 0;
}
클래스명* 배열이름[크기]
#include <iostream>
#include <cstring>
using namespace std;
class Person {
private:
char* name;
int age;
public:
Person(char* name, int age){
int len = strlen(name) + 1;
this->name = new char[len];
strcpy(this->name, name);
this->age = age;
cout<<"인자 생성자 호출"<<endl;
}
void SetInfo(char* name, int age) {
this->name = name;
this->age = age;
}
void Show() const {
cout<<"이름: "<<name<<endl;
cout<<"나이: "<<age<<endl;
}
};
int main(){
Person* arr[3]; //객체 배열
char namestr[10];
int age;
//객체를 생성한뒤, 객체 포인터에 그 주소를 대입하여 초기화
for(int i=0; i<3 ; i++){
cout<<"이름을 입력하시오: ";
cin>>namestr;
cout<<"나이를 입력하시오: ";
cin>>age;
arr[i] = new Person(namestr, age);
}
//저장된 객체 배열 출력
for(int i=0; i<3; i++){ arr[i]->Show(); }
return 0;
}
객체를 배열형태로 저장할 때는 배열에 저장되는 대상을 ‘객체'로 하는지[객체 배열], ‘객체의 주소'로 하는지[객체 포인터 배열]에 따라 다른 방법으로 배열을 선언해야한다.
this→num = num;
this.
) C++에서 this는 포인터이기 때문에, 참조한 뒤에 접근((*this).
or this→
)하게 된다. #include <iostream>
using namespace std;
class ClassEx {
private:
int num;
public:
ClassEx(int num) {
this->num = num;
cout<<"생성자 호출"<<endl;
}
ClassEx**&** Add(int num) {
this->num += num; //숫자를 더함
return *this; //자기자신 객체를 반환
}
ClassEx**&** Show() {
cout<<num<<endl; //숫자를 출력
return *this; //자기자신 객체를 반환
}
};
int main(){
ClassEx cls(10);
ClassEx **&ref** = cls.Add(5); //반환된 객체참조자를 참조자에 저장
cls.Show(); //15
ref.Show(); //15
ref.Add(5).Show().Add(5).Show(); //20, 25
cls.Show(); //25
return 0;
}
본문은 ⟪열혈 C++ 프로그래밍, 윤성우⟫ 도서에 기반하여 정리한 내용입니다.