[C++문법] 객체의 다양한 활용-1
본문 바로가기

C#

[C++문법] 객체의 다양한 활용-1

728x90
반응형

오늘은 객체의 다양한 활용에 대해 알아보겠습니다.

 

교재는 C++하이킹 책을 이용했습니다..

 

1. 객체의 포인터

일반변수에도 포인터 변수가 있듯이 객체에도 포인터 변수가있다.

 

객체포인터 변수 기본형식

클래스명 * 객체포인터 변수;

 

객체포인터 변수는 특정 객체 변수의 주소값을 저장하고 있어야한다.

 

객체포인터사용하기

#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;
cout << "object x =>";
x.showcomplex();
cout << "object y=>";
y.showcomplex();

complex* p;
p = &x;
cout << "p=>";
p->showcomplex();
p = &y;
cout << "p=>";
p->showcomplex();
}

 

내부 포인터 this

this는 컴파일러에 의해 생성되는 포인터로, 멤버함수를 호출한 객체를 가르키고 멤버함수에서만 사용할 수 있다.

 

this 포인터 정리

1. this 포인터는 멤버함수 내에서 호출 객체의 주소를 저장하는 포인터

2. this포인터는 컴파일러에 의해 제공되므로 프로그래머가 별도로 선언하지 않아도됨

3. 객체에의해 멤버함수가 호출되면 컴파일러는 호출한 객체의 주소를 멤버함수 내의 this포인터에 저장한다

4. 멤버함수 내에서 멤버변수를 참조하거나 다른 멤버함수를 호출할 떄 묵시적으로 this 포인터로 접근

5. 프로그래머가 this 포인터를 멤버변수나 멤버함수에 직접 붙여도 상관없다.

 

객체포인터 this 를 반드시 사용해야하는 경우는 함수의 매개변수와 멤버변수명이 동일해서 이를 구분 할 떄 이다.

 

this 포인터를 명시적으로 사용하기

#include<iostream>
using namespace std;
class complex {
private:
int real;
int image;
public:
complex(int real = 0, int image = 0);
void showcomplex() const;
};
complex::complex(int real, int image) {
this->real = real;
this->image = image;
}
void complex::showcomplex()const {
cout << "(" << real << "+"<< image << "i)" << endl;
}
void main() {
complex x(10, 20);
cout << "object x =>";
x.showcomplex();
}

 

클래스로 선언된 객체도 함수의 매개변수로 사용할 수 있다.

동일한 클래스형으로 선언된 객체끼리는 대입연산자로 값을 치환할 수 있다.

객체 단위로 치환하면 객체내의 모든 멤버변수값이 복사된다.

 

 

객체단위로 값 치환하기

#include<iostream>
using namespace std;
class complex {
private:
int real;
int image;
public:
complex(int r = 0, int i = 0);
void showcomplex()const;
void setcomplex(int r = 0, int i = 0);
};
complex::complex(int r, int i) {
real = r;
image = i;
}
void complex::showcomplex()const {
cout << "(" << real << "+" << image << "i)"<<"\n";
}

void complex::setcomplex(int r, int i) {
real = r;
image = i;
}
void main() {
complex x(10, 20);
complex y;
cout << "x=>";
x.showcomplex();
cout << "y=>";
y.showcomplex();
cout << "-------------------------------\n";
y = x;
cout << "x=>";
x.showcomplex();
cout << "y=>";
y.showcomplex();
cout << "-------------------------------\n";
y.setcomplex(30, 40);
cout << "x=>";
x.showcomplex();
cout << "y=>";
y.showcomplex();
}

 

값에 의한 전달 방식은 함수를 호출할 때 기술한 실 매개변수의 값만 함수 측의 형식 매개변수로 전달된다.

 

객체의 값에 희한 전달 방식의 함수 작성하기

#include<iostream>
using namespace std;
class complex {
private:
int real;
int image;
public:
complex(int r = 0, int i = 0);
void showcomplex()const;
void setcomplex(int r = 0, int i = 0);
};
complex::complex(int r, int i) {
real = r;
image = i;
}
void complex::showcomplex()const {
cout << "(" << real << "+" << image << "i)"<<"\n";
}

void complex::setcomplex(int r, int i) {
real = r;
image = i;
}
void copycomplex(complex des, complex src) {
des = src;
}
void main() {
complex x(10, 20);
complex y(30, 40);
cout << "x=>";
x.showcomplex();
cout << "y=>";
y.showcomplex();
cout << "--------------------------\n";
copycomplex(y, x);
cout << "x=>";
x.showcomplex();
cout << "y=>";
y.showcomplex();
}

값이 변하지않았다

-> 함수 내부에서 형식 매개변수인 src를 des에 복사하면 des값은 변경되지만 형식매개변수(des,src)는 실 매개변수(x,y)와는 별도의 기억공간이므로 함수 호출 후에 main 함수에서 실 매개변수 (x,y)를 출력해보면 값이 변경되지않음

 

결과값을 가져오기 위해서는 return을 사용해야한다.

결과값이 객체인 함수 작성하기 

#include<iostream>
using namespace std;
class complex {
private:
int real;
int image;
public:
complex(int r = 0, int i = 0);
void showcomplex()const;
void setcomplex(int r = 0, int i = 0);
};
complex::complex(int r, int i) {
real = r;
image = i;
}
void complex::showcomplex()const {
cout << "(" << real << "+" << image << "i)"<<"\n";
}

void complex::setcomplex(int r, int i) {
real = r;
image = i;
}
complex copycomplex(complex des, complex src) {
des = src;
return des;
}
void main() {
complex x(10, 20);
complex y(30, 40);
cout << "x=>";
x.showcomplex();
cout << "y=>";
y.showcomplex();
cout << "--------------------------\n";
y=copycomplex(y, x);
cout << "x=>";
x.showcomplex();
cout << "y=>";
y.showcomplex();
}

 

객체의 주소에 의한 전달 방식의 함수 작성하기

#include<iostream>
using namespace std;
class complex {
private:
int real;
int image;
public:
complex(int r = 0, int i = 0);
void showcomplex()const;
void setcomplex(int r = 0, int i = 0);
};
complex::complex(int r, int i) {
real = r;
image = i;
}
void complex::showcomplex()const {
cout << "(" << real << "+" << image << "i)"<<"\n";
}

void complex::setcomplex(int r, int i) {
real = r;
image = i;
}
void copycomplex(complex *pdes, complex src) {
*pdes = src;}
void main() {
complex x(10, 20);
complex y(30, 40);
cout << "x=>";
x.showcomplex();
cout << "y=>";
y.showcomplex();
cout << "--------------------------\n";
copycomplex(&y, x);
cout << "x=>";
x.showcomplex();
cout << "y=>";
y.showcomplex();
}

객체의 참조에 의한 전달 방식의 함수 전달하기

#include<iostream>
using namespace std;
class complex {
private:
int real;
int image;
public:
complex(int r = 0, int i = 0);
void showcomplex()const;
void setcomplex(int r = 0, int i = 0);
};
complex::complex(int r, int i) {
real = r;
image = i;
}
void complex::showcomplex()const {
cout << "(" << real << "+" << image << "i)"<<"\n";
}

void complex::setcomplex(int r, int i) {
real = r;
image = i;
}
complex & copycomplex(complex &des,const complex &src) {
des = src;
return des;
}
void main() {
complex x(10, 20);
complex y(30, 40);
complex z;

z = copycomplex(y, x);
cout << "x=>";
x.showcomplex();
cout << "y=>";
y.showcomplex();
cout << "z=>";
z.showcomplex();
}

정적 멤버변수와 정적 멤버함수

정적 멤버변수는 클래스의 인스턴스와 상관없이 프로그램의 시작과 동시에 생성된다.

 

정적 멤버변수의 특징

1. 정적 멤버변수는 클래스의 모든 인스턴스(객체)에 의해 공유된다.

2. 정적 멤버변수에 자료가 저장되어 값이 유지되는 원리는 전역변수와 동일하다. 하지만 정적 멤버변수는 해당 클래스명으로 접근해야 한다는 점에서 전역변수와 차이가 난다.

 

정적 멤버변수를 사용하기 위한 2가지 조건

1. 정적 멤버변수는 특정 클래스 내부에 선언해야한다.

2. 정적 멤버변수는 클래스 밖에서 별도로 초기화되어야 한다.

 

예시

class statictest{

public:

static int a;

int b;

}

 

int statictest::a=10;

 

클래스 statictest는 a,b라는 멤버 2개를 갖는다. a는 static예약어로 선언된 변수로. 이를 클래스 단위 멤버변수라고한다. 지금까지 선언해 왔던 변수 형태인 b는 인스턴스 단위 멤버변수라한다.

 

클래스 단위 멤버변수와 인스턴스 단위 멤버변수의 차이점 알아보기

#include<iostream>
using namespace std;

class statictest {
public:
static int a;
int b;
statictest();
};
statictest::statictest() {
b = 20;
}
int statictest::a = 10;
void main() {
cout << "statictest::a=>" << statictest::a << "\n\n";
statictest s1, s2;
cout << "s1.a=>" << s1.a << "\ts2.a=>" << s2.a << "\n";
cout << "s1.b=>" << s2.a << "\ts2.b=>" << s2.b << "\n";
s1.a = 100;
cout << "s1.a=>" << s1.a << "\t";
cout << "s2.a=>" << s2.a << "\n\n";
s1.b = 100;
cout << "s1.b=>" << s1.b << "\t";
cout << "s2.b=>" << s2.b << "\n";
}

static으로 선언된 멤버들은 클래스 단위 당 한개만 생성되어 여러객체의 해당 멤버를 공유한다.

인스턴스들이 멤버변수를 개별적으로 가지고 있어서 객체 인스턴스별로 사용된다.

 

정적 멤버함수

정적 멤버변수를 다루기 위한 멤버함수는 인스턴스 차원이 아닌 클래스 차원에서 사용 가능하도록 설계해야하는데 이를 위해 제공하는 것이 정적 멤버함수다.

정적 멤버변수를 호출하듯이 정적 멤버함수 역시 클래스명으로 호출할 수 있다.

 

정적 멤버함수 정의하기

#include<iostream>
using namespace std;

class statictest {
private:
static int a;
int b;
public:
statictest();
static void seta(int new_a);
static int geta();
};
int statictest::a = 10;
statictest::statictest() {
b = 20;
}
void statictest::seta(int new_a) {
a = new_a;
}
int statictest::geta() {
return a;
}

void main() {
cout << "statictest::geta()=>" << statictest::geta() << "\n\n";
statictest s1, s2;
s1.seta(10000);

cout << "s1.geta()->" << s1.geta() << "\t";
cout << "s2.geta()->" << s2.geta() << "\n";
}

 

정적 멤버함수를 사용할 때의 주의사항

1. 정적 멤버함수에서는 this 포인터를 참조할 수 없다.

2. 정적 멤버함수에서는 인스턴스 변수를 사용할 수 없다.

3. 정적 멤버함수는 오버라이딩 되지 않는다.

 

정적 멤버함수 사용 시 주의점 살펴보기

#include<iostream>
using namespace std;

class statictest {
private:
static int a;
int b;
public:
statictest();
static void printa();
void printb();
};
int statictest::a = 10;
statictest::statictest() {
b = 20;
}
void statictest::printa() {
cout << "a : " << a << endl;
}
void statictest::printb() {
cout << "this->b : " << this->b << endl;
}

void main() {
statictest s1;
s1.printa();
s1.printb();
}

 

정적 멤버함수에서는 this 포인터를 사용하지 못한다.

인스턴스 멤버함수를 호출할 때 특정 객체로 접근해서 호출하면 이를 멤버함수에서는 this포인터로 관리한다.

 

정적 멤버변수의 유용한 사용 예

모든 인스턴스들이 멤버변수나 멤버함수를 공유해야하는 경우가 있는데 이럴 때 static예약어를 사용해야한다.

 

 

 

인스턴스의 개수를 세는 정적 멤버변수 이용하기

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

class cstud {
char name[30];
char hphone[20];
char email[30];
static int cnt;
public:
cstud(char* n = "성윤정", char* h = "010-777-7777", char* e = "pink@naver.com");
~cstud();
void prn();
static void prn_cnt();
};
int cstud::cnt = 0;
cstud::cstud(char* n, char* h, char* e) {
strcpy(name, n);
strcpy(hphone, h);
strcpy(email,e);
cnt++;
}
cstud::~cstud() {
cnt--;
}
void cstud::prn() {
cout << "이름 : " << name << endl;
cout << "핸드폰 : " << hphone << endl;
cout << "이메일" << email << endl;
}
void cstud::prn_cnt() {
cout << "\n현재까지 등록된 인원수 :" << cnt << "\n\n";
}

void main() {
cstud::prn_cnt();
cstud man1("전수빈", "010-9999-9999", "subin@naver.com");
man1.prn();
cstud man2("전원지", "010-7777-7777", "won@naver.com");
man2.prn();
cout << "\n#중간에 인원 수를 파악합니다.";
cstud man3;
man3prn();
cout << "\n클래스의 할당된 메모리 사이즈 : " << sizeof(cstud);
cout << "\n";
cstud::prn_cnt();
}

 
반응형