1

クラスを介して特定のものを表すことができる基本パッケージと、この機能を拡張したい別のパッケージを取得したというシナリオを考えます。

(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-classandのインスタンスのリストを調べて、それぞれの型に変更されることを期待して、すべてのインスタンスextended-a-test-classを呼び出す関数を取得しました。method-a例えば(slot-a (method-a a-test-class-instance)) > 21(slot-a (method-a extended-a-test-class-instance)) > 23

しかし、これを行おうとすると、次のように method-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}>)

どちらの方法でもコンパイルできないか、メソッドの効果が期待どおりではないため、どちらも実際には機能していません。クラスとメソッド定義が同じパッケージにある場合でも、すべて正常に動作します。

したがって、対応するパッケージに対処する必要なく、インスタンスでメソッドを呼び出すにはどうすればよいですか? (それができない場合は、Common-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
4

2 に答える 2

3

2 つの記号とが同一(:import-from test #:method-a)になるように を追加する必要があります。(defpackage :exttest)test:method-aexttest:method-a

現在定義されているように、2 つの別個のジェネリック関数exttest:method-aとがありtest:method-a、それぞれに 1 つのメソッドがあります。前者は に対して定義されてexttest:extended-a-test-classいませんが、後者は に対して別のメソッドを持っていませんexttest:extended-a-test-class

于 2013-09-25T01:28:34.787 に答える
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」という名前の別のパッケージでは、「FOO」という名前のパッケージで「FROB」という名前のシンボルを参照するには、 と書く必要があります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)
于 2013-09-25T02:01:36.347 に答える