5

表現が他の多くのクラスに共通する基本クラス(「A」と呼びましょう)があります。

したがって、「B」などの他のクラスを定義して、このクラスを含めます。

これらの他のクラス (B) のプロトタイプを設定して、A から継承されたスロットのデフォルト値を含めたいと思います。これは自然なことだと思いました。

setClass("A", representation(a="character"))
setClass("B", contains="A", prototype(a = "hello"))

しかし、それはエラーを生成します:

Error in representation[!slots] : object of type 'S4' is not subsettable

なぜこれが起こるのか分かりません。プロトタイプを省略すると、次のことができます。

setClass("B", contains="A")

次に、自分のジェネレーター関数をハックします。

new_B <- function(...){ 
           obj <- new("B", ...)
           obj@a = "hello"
           obj
         }

でプロトタイプに基づいてオブジェクトを作成しますnew_B()が、ジェネリックジェネレーターを使用してプロトタイプを作成するのに比べて、それはひどく粗雑で醜いnew("B")です...

4

2 に答える 2

5

質問に対する新しい回答を提供するのではなく、私のコメントを補足します。これは、引数を位置で一致させるソリューションです (クラス B の追加の表現を指定しているため)。

.A <- setClass("A", representation(a="character"))
.B <- setClass("B", representation(b="numeric"),
     prototype(a="hello"),
     contains="A")

.A()とへの呼び出しを.B()置き換えます。あるレベルでは、これはシンタックス シュガーですが、オブジェクトの構築をより透過的にすることができますnew("A")new("B")

## construct an object using B's prototype, like new("B", b=1:3)
> .B(b=1:3)
An object of class "B"
Slot "b":
[1] 1 2 3

Slot "a":
[1] "hello"

## construct an object using A's prototype, like new("B", new("A"), b=1:3)
> .B(.A(), b=1:3)
An object of class "B"
Slot "b":
[1] 1 2 3

Slot "a":
character(0)

new(2 番目の例では、またはへの名前のない引数がB継承されたクラスの初期化に使用されるという事実を使用しています)。

.Aorを直接使用しなければならないのは、ユーザーにとってあまり友好的ではありません.B。たとえば、署名が正しく...、「クラス A のスロットの定義を参照」として文書化されているためです。これにより、OOP の強みであるインターフェイスと実装の分離が妨げられます。また、最後のコード チャンク (.B(.A(a=a), b=b)または.B(a=a, b=b)) のいずれかの動作が意図されていない可能性があります。代わりに、ユーザーに公開される関数を提供しおそらく初期データ マッサージを行います。

A <- function(a=character(), ...) {
    ## nothing special, just a public constructor
    .A(a=a, ...)
}

B <- function(b, a="hello", ...) {
    a <- tolower(a)  ## no SHOUTing!
    .B(A(a=a), b=b)  ## A's public interface; no need for B to know A's details
}

関数 A と B はインターフェイスを定義し、コンストラクターをクラス定義に関連付けることなく、ユーザーに受け入れ可能な引数に関するヒントを提供し、予備的なデータ マッサージを実行します。後者はinitializeメソッドを不要にすることができますが、これは良いことです。なぜなら、これらは複雑なコントラクト(初期化てコピー コンストラクターにする必要があり、上で見たように、名前のない引数は基本クラスを初期化する必要がある) を持っているからです。違う。

ほとんどの場合、これらは私の意見です。

于 2013-08-13T02:01:09.407 に答える
2

引数に名前を付けるだけです。

setClass("A", representation(a="character"))
setClass("B", contains="A", prototype=prototype(a="hello"))
于 2013-08-12T22:27:07.773 に答える