2013-09-25 6 views
1

클래스를 통해 특정 항목을 나타낼 수있는 기본 패키지와이 기능을 확장하려는 다른 패키지가 있다고 가정하면 szenario가 주어집니다. 외국 패키지에서 메소드를 오버로드하는 방법

(defpackage :test 
    (:use :cl) 
    (:nicknames :test) 
    (:export a-test-class 
     method-a 
     slot-a)) 

(in-package :test) 

(defclass a-test-class() 
    ((slot-a 
    :initform 42 
    :reader slot-a))) 


(defmethod method-a ((a-test-class a-test-class)) 
    (setf (slot-value a-test-class 'slot-a) 21) 
    a-test-class) 


(defpackage :exttest 
    (:use :cl) 
    (:export extended-a-test-class 
     method-a)) 

(in-package :exttest) 

(defclass extended-a-test-class (test:a-test-class) 
    ((slot-b 
    :reader slot-b 
    :initform nil))) 

(defmethod method-a ((a-test-class extended-a-test-class)) 
    (setf (slot-value a-test-class 'slot-a) 23) 
    a-test-class) 

지금 난 정말 anthying하지만 a-test-classextended-a-test-class의 인스턴스의 목록을 통해 가서 자신의 유형에 각각이를 변경할 기대, 그들 모두에 method-a를 호출하도록되어하지 않는 기능을 얻었다. 예 : (slot-a (method-a a-test-class-instance)) > 21

(slot-a (method-a extended-a-test-class-instance)) > 23 그러나이 일을하려고, 나는 제대로 방법-A를 호출의 문제로 실행 등 :

(defparameter *test-instance* (make-instance 'test:a-test-class)) 
(defparameter *ext-test-instance* (make-instance 'exttest:extended-a-test-class)) 

(test:slot-a (test:method-a *test-instance*)) 
> 21 
(test:slot-a (test:method-a *ext-test-instance*)) 
> 21 

또는

(test:slot-a (exttest:method-a *test-instance*)) 
(test:slot-a (exttest:method-a *ext-test-instance*)) 

debugger invoked on a SIMPLE-ERROR in thread 
#<THREAD "main thread" RUNNING {1002B03193}>: 
    There is no applicable method for the generic function 
    #<STANDARD-GENERIC-FUNCTION EXTTEST:METHOD-A (1)> 
    when called with arguments 
    (#<TEST:A-TEST-CLASS {10041148A3}>) 

은 둘 다 정말 같이 나를 위해 작동하지 않습니다 컴파일 할 수 없거나 메소드의 효과가 원하는대로되지 않습니다. 클래스와 메소드 정의가 같은 패키지에 있다면 모든 것이 잘 작동합니다.

따라서 : 해당 패키지를 처리 ​​할 필요없이 인스턴스에서 메소드를 호출하려면 어떻게해야합니까? 어떤 출력 내가 좋겠,에 "작업"예를 들어

(나는 그렇게 할 수 아니에요, 난이 공통 리스프에서 OO - 프로그래밍에 대한 나의 기대는 잘못된 얼마나 알고 싶습니다)이 C++ 프로그램을 코딩했습니다. CLOS는 메소드가 클래스에 "속하지"않는다는 사실 때문에 "일반적인"객체 지향 시스템과는 다른 것으로 알려져 있습니다. 하지만 (어떻게 든)에 대한 객체 지향 시스템을 기대하는 행동을 할 수있을 것입니다 /이처럼 사용할 수 :

#include <iostream> 

namespace test { 
    class sub { 
    public: 
    virtual sub* method_a() = 0; 
    }; 

    class a_test_class : public sub 
    { 
    protected: 
    int value; 
    public: 
    a_test_class(int val) : value(val) { 
    } 

    a_test_class* method_a() { 
    value = 21; 
    return this; 
    } 

    int get_value() { 
     return value; 
    } 
    }; 
} 

namespace exttest { 

    class extended_a_test_class : public test::a_test_class { 

    public: 
    extended_a_test_class(int val) : a_test_class(val) { } 

    extended_a_test_class* method_a() { 
    std::cout << "calling overloaded method" << std::endl; 
    this->value = 23; 
    return this; 
    } 
    }; 
} 


int main(int argc,const char* argv[]) { 
    test::a_test_class* atc = new test::a_test_class(42); 
    test::a_test_class* eatc = new exttest::extended_a_test_class(42); 
    std::cout << atc->method_a()->get_value() << std::endl; 
    std::cout << eatc->method_a()->get_value() << std::endl; 
    delete atc; 
    delete eatc; 
} 

> ./a.out 
21 
calling overloaded method 
23 
+1

메소드는 클래스에 속하지 않을 수 있지만 일반 함수에 속합니다. 일반적인 메소드를 정의하기 전에 (defgeneric을 사용하여) 일반 함수를 정의하는 것이 일반적으로 도움이된다는 것을 알게되었습니다. 최소한 SBCL은 암시 적으로'defmethod'로 제네릭 함수를 생성 할 때 경고를줍니다. 그게 너를 도왔을거야. – Svante

+0

@Svante 새 일반 메서드가 정의되어 있음을 알았지 만이를 방지하는 방법을 알지 못했습니다. 그러나 여전히 귀중한 조언, 감사합니다. – Sim

답변

3

당신은 그래서 두 심볼 test:method-aexttest:method-a이 될 것 (defpackage :exttest)(:import-from test #:method-a)를 추가 할 필요가 동일 .

가 현재 정의 된 바와 같이, 두 별도 일반적인 기능과 exttest:method-atest:method-a 하나에있어서 각각이있다; 전자는 exttest:extended-a-test-class에 대해서는 정의되어 있지 않지만 후자는 exttest:extended-a-test-class에 대한 별도의 방법이 없습니다.

2

함수 또는 방법을 호출 할 때 올바른 기호를 참조하도록 패키지 접두사를 써야하는 것처럼 패키지 접두사를 사용해야 할 수도 있습니다. 일반 함수에 대해 추가 메서드를 정의합니다. 예를 들어, "FOO"라는 이름의 패키지 및 패키지 "FOO"에서 "FROB"라는 이름의 일반적인 기능을 고려

(defpackage #:foo 
    (:export #:frob) 
    (:use "COMMON-LISP")) 

(in-package #:foo) 

(defgeneric frob (object)) 

(defmethod frob ((x string)) 
    (format t "frobbing string ~a" x)) 

;; call frob 
(frob "some string") 

동안 "FROB"라는 심볼을 참조, "ΒΑR"라는 또 다른 패키지 "FOO"라는 패키지에서 foo:frob을 작성해야합니다. 이것은 일반적인 펑크 인 (functoin)을 호출 할뿐만 아니라 그것에 대한 새로운 메소드를 정의하기위한 것입니다.

(defpackage #:bar 
    (:use "COMMON-LISP")) 

(defmethod foo:frob ((x integer)) 
    (format t "frobbing integer ~A" x)) 

;; call frob 
(foo:frob "some string") 
(foo:frob 45) 
관련 문제