2013-09-25 34 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

但試圖做到這一點,我碰上的正確調用方法,一個問題是:

(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}>) 

既不是真正的工作對我來說,在無論哪種方式我都無法編譯,或者方法的效果不符合要求。如果類和方法定義在同一個包中,但一切正常。

因此:如何在不需要訪問相應軟件包的情況下調用實例上的方法?(如果我不能這樣做,我想知道我在共Lisp的面向對象編程的期望如何被誤導)

對於「工作」例如,輸出什麼我想像,我編碼這個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

您需要添加(:import-from test #:method-a)(defpackage :exttest)這樣兩個符號test:method-aexttest: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") 

雖然名爲「ΒΑR」,是指一個名爲「FROB」的象徵另一個包在名爲「FOO」的包中,我們必須編寫foo:frob。這用於調用通用函數,並定義新的方法。

(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) 
相關問題