[C++] C++클래스와 객체 공부하기
본문 바로가기

C#

[C++] C++클래스와 객체 공부하기

728x90
반응형

오늘은 C++클래스와 객체에 대해 공부했습니다.

 

책은 C++하이킹책을 보며 공부했습니다.

 

C++의 특징은 객체지향 프로그래밍이다.

객체지향 프로그래밍은 우선 클래스를 선언한 후 이를 인스턴스(객체)화해서 프로그램을 작성한다.

클래스 예약어는 class이다.

class는 자료를 추상화해서 사용자 정의 자료형으로 구현할 수 있게 하는 도구이다.

클래스는 기억공간을 확보하는 것은 물론이고 이 클래스를 다룰 수 있는 방법도 구현해야한다.

 

클래스는 클래스 선언과 클래스 멤버함수 정의로 구성된다.

클래스선언은  구조체에는 없었던 접근 지정자가 추가된다.

접근지정자는 클래스에서 각 멤버변수나 멤버함수 앞에 붙여 각각에 대한 접근 권한을 지정해준다

private , public , protected 3가지가 있다.

 

private는 해당 멤버가 속한 클래스의 멤버함수에서만 사용할 수 있기 때문에 선언된 멤버는 캡슐화(데이터 은닉)이 된다.

public은 선언된 멤버들은 객체를 사용할 수 있는 범위라면 어디서나 접근이 가능한 공개된 멤버이다.

private멤버를 해당 클래스 외부에서 사용하도록 하기 위한 멤버함수를 정의할 때 사용

 

클래슨 새로운 자료형이 되고 테이터는 멤버변수가, 데이터를 처리할 함수는 멤버함수가 된다.

 

클래스 멤버함수 구현

함수의 3요소는 정의, 선언 , 호출이다.

-> 멤버함수도 이 3가지 조건을 만족해야한다.

우선 멤버함수의 정의를 알아보면

1. 멤버함수를 정의 할 때 함수명 앞에 클래스명을 명시해야한다.

클래스명 다음에 스코프연산자(::)를 사용한다.

2. 클래스의 멤버함수를 정의하는 목적은 클래스 내에 정의된 private멤버에 접근해서 이를 다루기 위해서이다.

그래서 멤버함수를 '메소드'라고 한다.

 

객체선언과 멤버참조

클래스는 추상적인 개념이고 객체는 '이름'과 같이 구체적인 실체이다.

클래스는 추상화된 자료형이므로 클래스로는 프로그램내에서 실질적인 작업을 수행하지 못한다.

따라서 객체를 선언해야하는데 객체는 클래스를 실체(instance)화한 것이다. 객체=인스턴스

 

int a;

위에 보면 자료형 int가 클래스에 해당되고 변수명 a가 객체에 해당한다.

자료형 int는 변수 a를 만들어내기 위한 형틀, 즉 템플릿이다.

클래스도 객체를 생성해내기 위한 일종의 형틀로 이해하면 쉽다.

 

클래스 멤버의 접근방법

멤버를 사용하려면 구조체처럼 .이나->멤버참조 연산자를 사용하면된다.

EX)

객체명.멤버변수;

객체명.멤버함수();

 

클래스에서 범하기 쉬운실수

complex가 클래스일 경우

complex.real=2;

이러면 컴파일에러가난다.

int=5;

이런 느낌

 

복소수 클래스로 설계하기

#include<iostream>
using namespace std;

class complex {
private:
int real;
int image;
public:
void setcomplex();
void showcomplex();
};
void complex::setcomplex() {
real = 2;
image = 5;
}
void complex::showcomplex() {
cout << real << "+" << image << "i" << endl;
}
void main() {
complex x, y;
x.setcomplex();
x.showcomplex();
y.setcomplex();
y.showcomplex();
}

클래스의 접근지정자, private/public

private 접근지정자

접근지정자가 생략되면 기본(default)으로 private가 적용된다.

일반적으로 멤버변수는 private로 선언한다.

 

public접근지정자

public : 을명시적으로 기술해야함

클래스 내에 멤버함수에서는 물론 객체가 선언되어 있는 영역이라면 어디서든지 객체명 다음에 멤버참조 연산자(.)로 연결해서 멤버함수를 사용할수 있다.

 

private멤버 성격 파악하기

private 멤버변수인 real과 image는 main함수내에서는 사용할 수 없으므로 컴파일 에러가 발생한다.

 

이 예제의 에러를 해결하는 방법은 크게 2가지가 있다.

1. 접근지정자를 퍼블릭으로 변경

2. 멤버변수를 직접접근 할 수 없기 때문에 이런 작업을 할 수 있는 멤버함수를 추가한다.

멤버변수의 값을 변경하는 로직을 멤버함수에 기술하고 특정 멤버변수의 값을 변경하기 위해 멤버함수를 호출하면 된다.

 

private멤버를 다루기 위한 멤버함수 추가하기

#include<iostream>
using namespace std;

class complex {
private:
int real;
int image;
public:
void setcomplex();
void showcomplex();
void setreal(int r);
void setimage(int i);
};
void complex::setcomplex() {
real = 2;
image = 5;
}
void complex::showcomplex() {
cout << real << "+" << image << "i" << endl;
}
void complex::setreal(int r) {
real = r;
}
void complex::setimage(int i) {
image = i;
}

void main() {
complex x;
x.setreal(5);
x.setimage(10);
x.showcomplex();
}

 

인라인 함수 다시보기

인ㄹ인 함수는 매크로 함수와 실행 원리가 동일하다

즉, 함수가 호출될 때 그 위치에 해당 함수가 삽입되도록 하는 것이다.

인라인 함수는 주로 정의가 짧을 때 사용한다.

 

인라인함수 기본 형식

 inline 자료형 함수명(매개변수리스트){

변수 선언;

문장;

return (결과값);

}

자동인라인 함수

멤버함수의 저으이가 아주 짧으면 클래스 선언 내부에 함수를 직접 정의 할 수 도 있다.

그리고 클래스내부에 정의된 함수는  함수 선언 앞에 inline이 없어도 자동으로 인라인함수가 된다.

 

인라인 함수사용하기

#include<iostream>
using namespace std;

class complex {
private:
int real;
int image;
public:
void setcomplex() {
real = 2;
image = 5;
}
void showcomplex();
};
inline void complex::showcomplex() {
cout << real << "+" << image << "i" << endl;
}
void main() {
complex x;
x.setcomplex();
x.showcomplex();
}

클래스 선언부에 멤버함수를 정의하면 자동인라인 함수가 된다.

 

const상수와 const멤버함수 

반드시 초깃값을 주어야한다.

const상수 기본형식

const 자료형 변수명 = 초깃값;

 

클래스의 멤버함수를 정의할 때 const를 선언해서 멤버함수 내에서 어떤 멤버변수 값도 변경하지 못하도록 할 수 있다.

 

const 멤버함수 사용하기

#include<iostream>
using namespace std;

class complex {
private:
int real;
int image;
public:
void setcomplex();
void showcomplex() const;
};
void complex::showcomplex() const{
cout << real << "+" << image << "i" << endl;
}
void complex::setcomplex() {
real = 2;
image = 5;
}
void main() {
complex x;
x.setcomplex();
x.showcomplex();
}

setcomplex멤버함수는 멤버변수 값을 변경하므로 const로 지정할 수 없다.

showcomplex함수 내부에서 멤버변수 값이 변경되지 말아야하므로 예약어const함수를 뒤에 기술해서 const함수로 정의한다.

 

함수의 오버로딩

C++에서는 다음과 같이 동일한 이름으로 함수를 여러번 정의해서 사용할 수 있다.

void print(int);

void print(long);

void print(int,long);

그래서 각 함수를 구분하기 위한것이 필요한데 이걸 '시그니처'라 한다.

 

함수의 시그니처

함수 여러 개 중에서 특정함수가 호출되면 컴파일러가 특정 함수를 구분해서 수행할 수 있어야한다.

함수를 구분하기 위한 구성요소를 시그니처라고한다.

 

즉, 함수의 오버로딩은 함수명을 동일하게 해서 여러번 오버로딩하되 함수를 호출할 때 모호하지 않도록 하려고 매개변수의 개수나 매개변수의 자료형을 다르게 주는 것을 의미한다.

 

함수의 오버로딩 살펴보기

#include<iostream>
using namespace std;

void printstr(char*);
void printstr(char, int);
void main() {
printstr("I'm sorry");
printstr('a', 3);
}
void printstr(char* the_string) {
cout << the_string << endl;
}
void printstr(char the_char, int repeat) {
for (int i = 0; i < repeat; i++) {
cout << the_char;
}
cout << endl;
}

 

함수의 오버로딩없이 절댓값구하기

#include<iostream>
using namespace std;
int myabs(int num) {
if (num < 0) {
num = -num;
}
return num;
}
double fmyabs(double num) {
if (num < 0) {
num = -num;
}
return num;
}
long int lmyabs(long int num) {
if (num < 0) {
num = -num;
}
return num;
}
void main() {
int a = -10;
cout << a << "의 절댓값은=>" << myabs(a) << endl;
double b = -3.4;
cout << b << "의 절댓값은=>" << fmyabs(b) << endl;
long int c = -20L;
cout << c << "의 절댓값은=>"<<lmyabs(c) << endl;

}

 

매개변수의 자료형이 다른 함수의 오버로딩을 이용해서 절댓값 구하기

#include<iostream>
using namespace std;
int abs(int num) {
if (num < 0) {
num = -num;
}
return num;
}
double abs(double num) {
if (num < 0) {
num = -num;
}
return num;
}
long int abs(long int num) {
if (num < 0) {
num = -num;
}
return num;
}
void main() {
int a = -10;
cout << a << "의 절댓값은=>" << abs(a) << endl;
double b = -3.4;
cout << b << "의 절댓값은=>" << abs(b) << endl;
long int c = -20L;
cout << c << "의 절댓값은=>"<<abs(c) << endl;

}

 

매개변수의 개수가 다른 함수의 오버로딩 살펴보기

#include<iostream>
using namespace std;

void print(int x, int y, int z) {
cout << x << " " << y << " " << z << endl;
}
void print(int x, int y) {
cout << x << " " << y << endl;
}
void print(int x) {
cout << x << endl;
}
void main() {
print(10, 20, 30);
print(10, 20);
print(10);
}

함수의 매개변수에 기본값 지정하기

#include<iostream>
using namespace std;

void print(int x = 0,int y = 0,int z = 0);
void main() {
print(10, 20, 30);
print(10, 20);
print(10);
print();
}
void print(int x, int y, int z) {
cout << x << " " << y << " " << z << endl;
}

클래스도 객체를 생성할 때 기본 자료형처럼 초깃값을 줄 수 있어야하는데, 이를 가능하게 하는 것이 생성자이다.

 

생성자의 특징

1. 생성자는 특별한 멤버함수이다.

2. 생성자명은 클래스명과 동일하다.

3. 생성자는 자료형(반환값의 유형)을 지정하지 않는다.

4. 생성자의 호출은 명시적이지 않는다.

5. 생성자는 객체를 선언(생성)할 때 컴파일러에 의해 자동으로 호출된다.

6. 객체의 초기화란 멤버변수의 초기화를 의미한다.

 

생성자를 명시적으로 만들지 않으면 C++컴파일러는 매개변수가 없는 생성자를 자동으로 만들어놓는다. 매개변수가 없는 생성자는 아무런 일도 하지 않는데 이러한 생성자를 기본 생성자라고한다.

complex x; => 기본생성자

 

멤버변수에는 쓰레기값이 저장된다.

 

매개변수가 없는 생성자 작성하기

#include<iostream>
using namespace std;

class complex {
private:
int real;
int image;
public:
complex();
void showcomplex()const;
};
complex::complex() {
real = 5;
image = 20;
}
void complex::showcomplex()const {
cout << real << "+" << image << "i" << endl;
}
void main() {
complex x;
x.showcomplex();
}

다양한 초깃값의 매개변수를 사용하는 생성자 작성하기

#include<iostream>
using namespace std;

class complex {
private:
int real;
int image;
public:
complex(int r,int i);
void showcomplex()const;
};
complex::complex(int r,int i) {
real = r;
image = i;
}
void complex::showcomplex()const {
cout << real << "+" << image << "i" << endl;
}
void main() {
complex x(10,20);
complex y(30, 40);
x.showcomplex();
y.showcomplex();
}

 

생성자 오버로딩하기

#include<iostream>
using namespace std;

class complex {
private:
int real;
int image;
public:
complex();
complex(int r,int i);
void showcomplex()const;
};
complex::complex() {
real = 0;
image = 0;
}
complex::complex(int r,int i) {
real = r;
image = i;
}
void complex::showcomplex()const {
cout << real << "+" << image << "i" << endl;
}
void main() {
complex x(10,20);
complex y(30, 40);
complex z;
x.showcomplex();
y.showcomplex();
z.showcomplex();
}

 

생성자의 기본 매개변수 값 설정하기

#include<iostream>
using namespace std;

class complex {
private:
int real;
int image;
public:
complex(int r=0,int i=0);
void showcomplex()const;
};
complex::complex(int r,int i) {
real = r;
image = i;
}
void complex::showcomplex()const {
cout << real << "+" << image << "i" << endl;
}
void main() {
complex x(10,20);
complex y(30);
complex z;
x.showcomplex();
y.showcomplex();
z.showcomplex();
}

 

생성자의 콜론초기화

생성자는 객체를 초기화하기 위한 멤버함수이다,

생성자의 머리부분에서 멤버변수에 초깃값을 설정할 수 있다.

함수의 몸체 기술되어야 할 멤버변수의 초깃값 설정을 함수의 머리 부분으로 옮기되 콜론으로 멤버변수를 초기화된다고 알린다.

 

생성자 콜론 초기화하기

#include<iostream>
using namespace std;

class complex {
private:
int real;
int image;
public:
complex(int r=0,int i=0);
void showcomplex()const;
};
complex::complex(int r,int i):real(r),image(i)
{
}
void complex::showcomplex()const {
cout << real << "+" << image << "i" << endl;
}
void main() {
complex x(10,20);
complex y(30);
complex z;
x.showcomplex();
y.showcomplex();
z.showcomplex();
}

 

소멸자의 의미와 특징

소멸자는 생성자의 반대개념이다

1. 소멸자는 객체가 소멸될 때 자동으로 호출

2. 소멸자는 객체를 정리해 주는(리소스를 해제한다든지 하는 작업)멤버함수이다.

 

소멸자의 특징

소멸자도 매개변수가 없는 기본생성자를 C++컴파일러로부터 자동으로 제공받는다.

모든 클래스에 명시적으로 기술하지 않아도된다.

객체가 소멸될때 해야 할 일이 있다면 프로그래머가 직접 명시해주어야한다.

 

1. 소멸자 함수는 멤버함수다

2. 소멸자 함수명도 생성자처럼 클래스명을 사용한다.

3. 소멸자 함수는 생성자 함수와 구분하려고 함수명 앞에 ~기호를 붙인다.

4 . 소멸자는 자료형을 지정하지 않는다.(반환값의 유형을 지정하지 않는다)

5. 소멸자의 호출은 명시적이지 않다.

6. 소멸자는 객체 소멸 시 자동 호출된다.

7. 소멸자는 전달 매개변수를 지정할 수 없다.

8. 소멸자는 전달 매개변수를 지정할 수 없으므로 오버로딩 할 수 없다.

 

소멸자 정의하기

#include<iostream>
using namespace std;

class complex {
private:
int real;
int image;
public:
complex(int r=0,int i=0);
~complex();
void showcomplex()const;
};
complex::complex(int r,int i):real(r),image(i)
{
}
void complex::showcomplex()const {
cout << real << "+" << image << "i" << endl;
}
complex::~complex() {
cout << "소멸자가 호출된다." << endl;
}
void main() {
complex x(10,20);
complex y(30);
complex z;
x.showcomplex();
y.showcomplex();
z.showcomplex();
}

 

이상으로 클래스와 객체 포스팅 마치겠습니다.

반응형