C++는 객체지향을 도입한 언어로서, 클래스를 정의할 수 있고 클래스에 대한 멤버 변수에 접근지정자를 부여할 수 있다. (private, protected, public)
private, protected, public의 의미는 알고 있다는 가정하에 이곳에서는 설명을 생략한다.
본론으로 바로 들어가서, 다음의 소스코드를 보면...
#include <iostream> class Point { private: int x_; int y_; public: Point() : x_(0), y_(0) {} Point(int x, int y) : x_(x), y_(y) {} Point(const Point &ref) : x_(ref.x_), y_(ref.y_) {} ~Point() {} void add_this(Point &ref) { x_ += ref.x_; y_ += ref.y_; } static Point add_new(Point &ref_a, Point &ref_b) { Point result; result.x_ = ref_a.x_ + ref_b.x_; result.y_ = ref_a.y_ + ref_b.y_; return result; } void show( const char *str ) { std::cout << str << " : x[" << x_ << "] y[" << y_ << "]" << std::endl; } }; int main() { Point p1(100, 200); Point p2(300, 400); p1.show("p1"); p2.show("p2"); std::cout << std::endl; p1.add_this(p2); p1.show("p1"); std::cout << std::endl; Point p3 = Point::add_new(p1, p2); p3.show("p3"); std::cout << std::endl; return 0; }
Point 클래스의 멤버 변수인 x_, y_ 는 private 변수이며, 자신의 멤버 함수들에 의해 접근하는 것은 당연히 허용한다. 그런데 문제는 멤버 함수 내부에서 다른 Point 클래스 객체를 생성하고 그 생성한 객체의 private 멤버 변수에 접근이 가능한지, 또는 멤버함수에서 다른 Point 클래스를 참조자로 받아 그 참조자로서 private 멤버 변수에 접근이 가능한지가 헷갈린다는 것이다.
위의 소스를 보면 add_new 함수는 자체적으로 Point 의 인스턴스를 생성한 후 그 인스턴스의 private 멤버변수에 바로 접근한다. 이 것이 컴파일이 가능하며 실행도 제대로 될까?
이상할 지도 모르지만, 위 소스는 아무런 문제 없이 컴파일 및 실행이 된다. 실행 결과는 다음과 같다.
p3 클래스가 아무런 문제 없이 p1, p2의 각 멤버 변수의 합이 저장된 인스턴스로 생성이 되었다.
여기서 알 수 있는 사실은, 우리가 사용하는 접근제어자의 접근 제어 기준은 그때 그때 생성된 인스턴스의 기준이 아니라 클래스 기준이라는 것이다. 즉, 서로 다른 인스턴스이더라도 그 인스턴스가 동일한 클래스 타입이면 각 멤버는 서로의 private 멤버 변수에 접근이 가능하다는 이야기가 된다.
이것이 무언가 대단한 이야기 같지만, 가만히 생각해보면 당연한 이야기이다. C++에서 사용할 수 있는 friend 키워드도 그때그때 생성되는 인스턴스 기준이 아닌 틀 (클래스, 혹은 함수) 기준이다. 상속 또한 인스턴스가 아닌 클래스 기준이다.
다른 관점에서 접근하더라도 마찬가지이다. 만일 private 접근지정자가 클래스가 아닌 인스턴스 기준이라면 C++에서 기본적으로 제공해 주는(그래고 사용자 정의도 가능한) 복사생성자와 대부분의 연산자 오버로딩은 애초에 존재할 수가 없었을 것이다. ^^
뭔가 private이 private 같지 않아보일 지 모르지만, 이 사실은 우리가 private 에 대하여 좀 더 정확한 개념을 짚고 넘어가는 데에 도움이 될 것이다.
그렇다면 C++보다 객체지향성이 더욱 강한 JAVA는 어떨까?
결론부터 말하면... JAVA도 마찬가지이다. 아래 소스를 보자.
class A 의 멤버 함수 test 안에서 다른 인스턴스 a를 선언한 후 a의 private 멤버 val에 직접 접근하여 값을 변경한다.
역시 정상 작동하며 결과는 다음과 같다.
물론 JAVA에서 저런 형태의 소스코드를 작성할 경우가 드물 수도 있지만, private의 대상 범주를 좀 더 확실히 하는 데에 도움이 될 만한 소스코드일 것 같다.
결론은... 이 한마디로 갈음할 수 있을 듯 하다.
C++의 클래스는 자기 자신을 friend 클래스로 간주한다.
### Wafting ....... Done !!!
### ...
### ;;
위의 소스를 보면 add_new 함수는 자체적으로 Point 의 인스턴스를 생성한 후 그 인스턴스의 private 멤버변수에 바로 접근한다. 이 것이 컴파일이 가능하며 실행도 제대로 될까?
이상할 지도 모르지만, 위 소스는 아무런 문제 없이 컴파일 및 실행이 된다. 실행 결과는 다음과 같다.
p1 : x[100] y[200] p2 : x[300] y[400] p1 : x[400] y[600] p3 : x[700] y[1000]
p3 클래스가 아무런 문제 없이 p1, p2의 각 멤버 변수의 합이 저장된 인스턴스로 생성이 되었다.
여기서 알 수 있는 사실은, 우리가 사용하는 접근제어자의 접근 제어 기준은 그때 그때 생성된 인스턴스의 기준이 아니라 클래스 기준이라는 것이다. 즉, 서로 다른 인스턴스이더라도 그 인스턴스가 동일한 클래스 타입이면 각 멤버는 서로의 private 멤버 변수에 접근이 가능하다는 이야기가 된다.
이것이 무언가 대단한 이야기 같지만, 가만히 생각해보면 당연한 이야기이다. C++에서 사용할 수 있는 friend 키워드도 그때그때 생성되는 인스턴스 기준이 아닌 틀 (클래스, 혹은 함수) 기준이다. 상속 또한 인스턴스가 아닌 클래스 기준이다.
다른 관점에서 접근하더라도 마찬가지이다. 만일 private 접근지정자가 클래스가 아닌 인스턴스 기준이라면 C++에서 기본적으로 제공해 주는(그래고 사용자 정의도 가능한) 복사생성자와 대부분의 연산자 오버로딩은 애초에 존재할 수가 없었을 것이다. ^^
뭔가 private이 private 같지 않아보일 지 모르지만, 이 사실은 우리가 private 에 대하여 좀 더 정확한 개념을 짚고 넘어가는 데에 도움이 될 것이다.
그렇다면 C++보다 객체지향성이 더욱 강한 JAVA는 어떨까?
결론부터 말하면... JAVA도 마찬가지이다. 아래 소스를 보자.
class A { private int val; public A() { this.val = 12345678; } public A(int i) { this.val = i; } public void test() { A a = new A(); a.val = this.val; System.out.println("val a = " + a.val); } public void show() { System.out.println("val = " + this.val); } } public class Test { public static void main( String[] arags ) { System.out.println("Test !!!"); A mainA = new A(87654321); mainA.show(); mainA.test(); } }
class A 의 멤버 함수 test 안에서 다른 인스턴스 a를 선언한 후 a의 private 멤버 val에 직접 접근하여 값을 변경한다.
역시 정상 작동하며 결과는 다음과 같다.
Test !!! val = 87654321 val a = 87654321
물론 JAVA에서 저런 형태의 소스코드를 작성할 경우가 드물 수도 있지만, private의 대상 범주를 좀 더 확실히 하는 데에 도움이 될 만한 소스코드일 것 같다.
결론은... 이 한마디로 갈음할 수 있을 듯 하다.
C++의 클래스는 자기 자신을 friend 클래스로 간주한다.
### Wafting ....... Done !!!
### ...
### ;;
전공학생인데 오늘 학교에서 시험보다 이 부분이 갑자길 헷갈렸는데 잘 알고 가요^^!! 감사합니다!
답글삭제고맙습니다. java에서 c++로 넘어가는 중에 좋은 글 잘 보고 갑니다.
답글삭제