#include <iostream>
using namespace std;
class Who
{
public:
void test() const
{
cout << "test...\n";
}
};
int main()
{
Who Obj1;
Obj1.test();
return 0;
} | |
위와같이 부르게되면 일반함수와 똑같다. 그렇다면 무슨 차이가 있을까?
class Who
{
public:
int i;
Who()
{
i = 9;
}
void test() const
{
cout << "test...\n";
i = 10;
cout << "i = " << i << endl;
}
}; | |
클래스의 내용을 위와같이 만들어보았다. 그러나 아래그림과같이 에러가 뜬다.
이렇게 다른 곳의 변수를 바꾸지 못한다.
그렇다면 인자를 받으면 어떻게 될까?
class Who
{
public:
int i;
Who()
{
i = 9;
}
void test(int iNum) const
{
cout << "test...\n";
//i = 10; //안에서 변경이 불가능하다. // const 함수 속성 위반, 컴파일불가.
iNum = 0;//인자로 들어온 값은 변경이 가능하다.
cout << "i = " << i << endl;
cout << "iNum = " << iNum << endl;
}
};
int main()
{
Who Obj1;
Obj1.test(1);
return 0;
} | |
위와같이 인자로 받을경우 컴파일이 잘된다. 즉, 인자로 받은함수는 변수로하되, 다른곳의 변수들은 상수화시킨다는것을 알수있다.
그리고 c++ 에선 특이한것이 있는데. 바로 this 이다. this가 뭐냐고 하면..
class Who
{
public:
int i;
Who()
{
i = 9;
}
void test(int iNum) const
{
cout << "test...\n";
//i = 10; //안에서 변경이 불가능하다. // const 함수 속성 위반, 컴파일불가.
iNum = 0;//인자로 들어온 값은 변경이 가능하다.
cout << "i = " << i << endl;
cout << "iNum = " << iNum << endl;
cout << this << endl; // c++에서 this를 쓰게되면,
//자기자신을 가르키는 클래스 포인터라고 생각할수있다.
}
};
int main()
{
Who Obj1;
Obj1.test(1);
return 0;
}
| |
위와같이 하게되면 아래그림과같이 자기 클래스의 주소를 가르킨다.
클래스 안의 static함수에 대해 알아보자.
class Who
{
public:
int i;
Who()
{
i = 9;
}
void test(int iNum) const
{
- 생략 -
}
static void testStatic()
{
cout << "testStatic\n";
}
};
int main()
{
//testStatic()을 호출해
Who::testStatic(); //스태틱 함수는 클래스객체 없이도 선언된다.
/*
Who Obj1;
Obj1.test(1);
Obj1.testStatic();
cout << &Obj1 << endl;
*/
return 0;
}
| |
위와같이 클래스 객체 없이도 선언이 된다.
그렇다면 아까본 this를 여기서 사용하면 어떻게 될까?
static void testStatic()
{
cout << "testStatic\n";
cout << this << endl;
}
int main()
{
//testStatic()을 호출해
Who::testStatic(); //스태틱 함수는 클래스선언 없이도 선언된다.
return 0;
}
| |
위와같이 스태틱함수안에 this를 넣으면 그림과같이 에러가 뜬다.
왜 이런것일까? 객체가 없어서 그런것일까?? 그렇다면 객체를 만들어보겠다.
class Who
{
public:
int i;
Who()
{
i = 9;
}
void test(int iNum) const
{
//생략 }
static void testStatic()
{
cout << "testStatic\n";
cout << this << endl;
}
};
int main()
{
//testStatic()을 호출해
//Who::testStatic(); //스태틱 함수는 클래스선언 없이도 선언된다.
Who Obj1;
Obj1.test(1);
Obj1.testStatic();
cout << &Obj1 << endl;
return 0;
}
| |
이렇게해도 역시 에러가 뜬다. 왜 이렇게 에러가뜨는거냐 하면..
static함수는 객체생성을 떠나서, 이미 먼저 만들어지기 떄문에 컴파일러에서 에러를 뛰운다.
도형을 그린다고 가정하고 아래와같이 소스를 짠다고 하자.
#include <iostream>
using namespace std;
class shape
{
public:
void draw()
{
cout << "shape::draw()\n";
}
};
class rectangle: public shape
{
public:
void draw()
{
cout << "ractangle::draw()\n";
}
};
class circle: public shape
{
public:
void draw()
{
cout << "circle::draw()\n";
}
};
int main()
{
shape * cpshape = new shape;
rectangle * cprectangle = new rectangle;
circle * cpcircle = new circle;
cpshape -> draw();
cprectangle -> draw();
cpcircle -> draw();
return 0;
} | |
위와같이하게 되면 그림과같이 순서대로 출력된다.
도형을 그리는대 도형이라는 부분이 필요할까?
당연히 필요없다. 도형은 그저 원,사각형,삼각형.. 등을 포함하고 있을뿐, 출력될 필요는 없다.
그렇다면, 이부분을 출력하지 않게 하기위해서는 아래와같이.
class shape
{
protected:
shape(){}//이렇게하면 절때생성할수업다.
public:
virtual void draw()
{
cout << "shape::draw()\n";
cout << "이건 추상적인 부분이기에 호출되면 부적당....\n";
}
}; | |
위와같이 생성자에 protected해주면 생성이 되지 않는다.
그리고, 도형의 draw함수는 부를 필요가 없기떄문에 virtual 로 해주면 아래그림과같이 필요한부분만 됨을 알수있다.
그리고 이렇게 된다면, 아래 소스와같이 간단하게 정리도 된다.
int main()
{
circle ObjCircle;
rectangle ObjRect;
//객체 기반 호출.
shape * cpShape1 = &ObjCircle;
shape * cpShape2 = &ObjRect;
cpShape1 -> draw();
cpShape2 -> draw();
return 0;
} | |
이런식으로 부모의 클래스로 포인터를 생성하여 가르키게되면, 모든 클래스를 제어할수 있게되며,
보는사람도 편하거니와, 정리도 깔끔하게 된다.
이런방식을
객체 기반 호출 이라고한다.
그런데 이것에는 문제가있다. 어떤 문제냐하면...
동적할당을 받어보자.
class shape
{
protected:
shape(){}//이렇게하면 절때생성할수업다.
public:
~shape()
{
cout << "shpae 소멸자\n";
}
};
class rectangle: public shape
{
public:
~rectangle()
{
cout << "rectangle 소멸자\n";
}
};
class circle: public shape
{
public:
~circle()
{
cout << "circle 소멸자\n";
}
};
int main()
{
circle ObjCircle;
rectangle ObjRect;
shape * cpShape1 = new circle;
shape * cpShape2 = new rectangle;
delete cpShape1;
delete cpShape2;
return 0;
}
| |
이렇게하면 아래그림과같이 일반적으로 객체를 선언했을때와, 동적할당을 했을때, 생성되는 소멸자가 다르다.
여기서 문제 점이 무엇이냐면, 위의 그림같은경우, circle 클래스가 만들어지며, 소멸할떄 둘이 같이 소멸한다.
하지만, 동적할당을 할 경우, 안의 함수호출은 되지만, circle 클래스의 소멸자가 뜨지가 않는다.
이 문제를 해결하기 위해서는.... 앞에서 하였던것 처럼 virtual을 해주게 되면 해결되게 된다.
class shape
{
protected:
shape(){}//이렇게하면 절때생성할수업다.
public:
virtual void draw()
{
cout << "shape::draw()\n";
cout << "이건 추상적인 부분이기에 호출되면 부적당....\n";
}
virtual ~shape()
{
cout << "shpae 소멸자\n";
}
}; | |
위와같이 하게되면 정상적으로 작동됨을 알수있다.
이렇게 동적할당을 받을경우, 좋은점이 무엇이 있을까? 아래소스를 보자.
int main()
{
shape * cpShape1 = new circle;
shape * cpShape2 = new rectangle;
cpShape1 -> draw();
// 동적 바인딩 이라고하며 동적할당을 받어서 사용하게되면
// 실행되기전에 주소를 받고 없어지기 떄문에,
// disassemble이 거의 불가능하다.
// 보안적으로 좋기때문에 사용한다.
cpShape2 -> draw();
delete cpShape1;
delete cpShape2;
return 0;
} | |
여기서 한가지더 문제점이 있다. 무슨 문제점이냐고 하면..
class triangle: public shape
{
public:
~triangle()
{
cout << "triangle 소멸자\n";
}
}; | |
위와같이 실수로 draw를 없이 소멸자만 만들었다고 치자.
그렇게 된다면 아래그림과 같이 shape의 draw함수가 호출된다.
draw함수가 호출되버렸다. 이렇게되면 분명 안되는것이다.
그렇다면 이문제를 어떻게 해결하면 될까?
해결법은 의외로 간단하다.
class shape
{
protected:
shape(){}//이렇게하면 절때생성할수업다.
public:
virtual void draw() = 0; // 이 함수는 없지만 꼭만들어라고 강요한다.
/*{
cout << "shape::draw()\n";
cout << "이건 추상적인 부분이기에 호출되면 부적당....\n";
}*/
virtual ~shape()
{
cout << "shpae 소멸자\n";
}
};
| |
위와같이 함수 = 0; 이라고 해주게되면, 아래그림과같이 에러를 뛰우며 draw함수를 만들라고 강요를 하게된다.
하지만, 자기자신은 draw라는 함수가 존재하지 않는다.
(그림을 자세히 보고싶으면 그림을 클릭해 주쎄용~)
이렇게 에러를 뛰우며 이 부분을 고치게되면
class triangle: public shape
{
public:
void draw()
{
cout << "circle::draw()\n";
}
~triangle()
{
cout << "triangle 소멸자\n";
}
}; | |
아래와 같이 잘 뜨게된다.
오탈자나 틀린부분 지적부탁드립니다 (__)