자바스크립트(ECMAScript 5) 객체의 공용 멤버와 공용 메소드는 다음과 같이 만드는 것이 일반적인 것 같다.


var A = function(name) {
   console.log("constructor A.");
   this.name = name; //공용 멤버
}
A.prototype = {
   who: function() { //공용 메소드
       console.log("I'm "+this.name);
   },
};


즉 공용 멤버는 생성자 함수 안에서 this 키워드로 만들어지고 공용 메소드는 prototype 객체 안에 정의한다.


 이제 이렇게 생성된 객체 A를 상속해서 새로운 객체 B를 정의하는 방법을 알아보자. 상속이란 기존 객체의 모든 공용 멤버를 복사하여 그대로 사용하면서 거기에 새로운 멤버나 메소드를 추가하는 방식으로 객체를 재사용하는 방법이다. 여러 방법 중에서 ECMAScript5 에서 도입된 Object.create() 함수를 사용하는 일반적인 방법은 다음과 같다.


var B = function(name, age) {
   console.log("constructor B.");
   A.call(this, name); // (1)공용멤버를 상속(복사)한다.
   this.age = age; // 새로운 멤버 추가
}
B.prototype = Object.create(A.prototype); //(2)공용메소드를 상속(복사)
B.prototype.constructor = B; //(3)생성자를 복원한다.
B.prototype.who2 = function() { // 새로운 메소드 추가
   console.log("I'm "+this.age+" years old.");
}


위에서 보면 세 가지 단계가 필수적이다.


(1) 공용 멤버를 상속(복사)하기 위해서 생성자 함수 내부에서 A.call() 함수나 A.apply()함수를 호출하여 공용 멤버들을 복사하는 단계

(2) 공용 메소드들을 복사하기 위해서 Object.create() 함수를 호출하는 단계

(3) 생성자를 복원하는 단계


만약 상속받는 객체의 생성자 함수의 인자들과 원 객체의 생성자 함수 인자들이 동일하다면 A.apply() 함수를 이용하여 인자 전체를 넘긴다.


A.apply(this, arguments);


그렇지 않고 일부만 선택적으로 사용한다면 예제와 같이 A.call()함수를 사용할 수 있다.





Posted by 살레시오
,

 파이썬은 클래스를 지원하므로 객체 지향적인 프로그래밍을 할 수 있다. 사실 지금까지 다뤄온 기본 자료형도 다 클래스이다. 클래스는 새로운 자료형을 정의하는 것이고 객체(object)는 클래스의 인스턴스(instance, 클래스가 구체화된 것)를 의미한다.


클래스는 다음과 같이 정의한다.


class 식별자:
클래스 본체


보통 클래스의 식별자는 대문자로 시작한다. 예를 들어 Person, Robot, Car, Point 등이다. 클래스 본체는 이 클래스에 속하는 변수와 함수를 정의하게 된다. 특별히 클래스에 속한 변수들을 필드(field), 클래스에 속한 함수들을 일반 함수들과 구분하기 위해서 메소드(method)라고 부르며 이 둘을 통칭하여 속성(attribute)라고 한다.


이 용어들에 대해서는 숙지해 두는 것이 좋다.


  • 필드 (field) : 클래스에 내장된 변수

  • 메쏘드 (method) : 클래스에 속하는 함수

  • 속성 (attribute) : 필드와 메쏘드를 통칭하여 속성이라 한다.


가장 간단한 형태의 클래스를 다음과 같이 정의해 보자.


class Robot:
pass


이 클래스는 보면 알겠지만 본체가 없다. 이 클래스의 인스턴스를 생성하려면 다음과 같이 하면 된다.


>>> asimo = Robot()


이제 asimo 는 Robot 클래스의 객체가 되었다. 이와 같이 어떤 클래스의 객체(인스턴스)를 생성하려면 다음과 같이 한다.


변수명 = 클래스명()


마치 함수를 호출하는 것과 유사하다.



Posted by 살레시오
,

  이미 생성된 인스턴스에 다른 인스턴스를 대입할 때 대입 연산자(=)가 이용되며 실제로는 복사가 수행된다. 다음과 같은 간단한 클래스를 고려해 보자.


-------------------------------------------

class Led {

    public :

        int pin;

        char *name;

};

-------------------------------------------


이 클래스는 복사 생성자도 없고 =연산자도 오버로딩되지 않았다. 이 경우 디폴트=연산자 함수는 얕은 복사를 수해하게 된다. 이제 다음과 같은 두 예를 보자


-------------------------------------------

//ex1

Led led1;

led1.pin=13;

Led led2 = led1; // 복사생성자 호출


//ex2

Led led1, led2;

led1.pin=13;

led2 = led1; // 대입 함수 호출

-------------------------------------------


<ex1>에서 led2가 생성될 때는 복사생성자가 실행되고  <ex2>에서는 대입 연산 함수가 호출된다.


하지만 멤버변수에 포인터가 있으므로 여기에 문자열이 저장된 경우 얕은 복사는 문제가 일어나게 된다. 


-------------------------------------------

Led led1, led2;

led1.name = new char[3];

strcpy(led1.name, "hi");


led2 = led1; // 얕은 복사가 일어나므로 문제를 야기함.

-------------------------------------------


심지어 깊은 복사를 수행하는 복사생성자가 정의되어 있어도 대입 연산자는 얕은 복사만을 수행하므로 주의해야 한다. 즉, 대입연산은 자동으로 사용자가 정의한 복사 생성자를 호출하지 않는다. 아래와 같이 깊은 복사를 수행하는 복사 생성자를 작성했다고 하자.


-------------------------------------------

class Led {

    public :

        int pin;

        char *namer;

        Led(const Led& src) {

            pin = src.pin;

            name = new char[strlen(src.name)+1];

            strcpy(name, src.name);

        }

};

-------------------------------------------


복사 생성자는 생성자이므로 인스턴스가 새로 생성될 때 수행된다. 따라서 name필드에 이전에 메모리를 할당한 적이 없을 것이니 해제할 필요도 없다.


  이렇게 작성한 뒤에서 대입연산은 여전히 얕은 복사를 수행하게 된다. 즉, 복사생성자와 대입연산자는 별개이다.  대입 시에도 깊은 복사를 수행하려면 대입연산자를 오버로딩하여 사용자가 작성해주어야 한다. 한 가지 주의할 점은 대입연산자는 이미 생성된 인스턴스에다 복사해 넣는 것이므로 기존의 문자열을 해제하는 코드가 추가로 필요하다는 것이다. 이것이 대입연산자와 복사생성자의 차이이다.


-------------------------------------------

Led& Led::operator= (const Led& src) {

    if (this == &src) return *this; // 자기 대입 방지


    pin = src.pin;

    i(name != NULL) delete[] name; // (주의)

        name = new char[strlen(src.name)+1];

        strcpy(str, src.name);


    return *this;

}

-------------------------------------------


이제는 대입연사자를 사용하면 깊은 복사가 일어나게 된다. 만약 복사 생성자와 코드가 많이 중복된다면 중복되는 부분은 private 멤버 함수로 따로 작성하는 것이 더 효율적일 것이다.

[#00063]


Posted by 살레시오
,