2013-08-12 14 views
5

私は、他の多くのクラスに共通する表現を持つ基本クラス( "A"と呼ぶ)を持っています。継承スロットのS4プロトタイプを定義する方法

したがって、私はこのクラスを含むために "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", ...) 
      [email protected] = "hello" 
      obj 
     } 

をしてからnew_B()とのプロトタイプに基づいて、私のオブジェクトを作成し、それはひどく原油と比べて醜いです一般的な発電機new("B")を使用して、私のプロトタイプを有することに...

答えて

2

は、あなただけの引数に名前を付ける必要があります。

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

また、 '.A < - setClass(" A "、表現(a ="文字 "))'は '.A()'または '.A(a =" foo ")"ではなく、新しい( "A") 'ではなくコンストラクタとして使用されます。 'A < - ...'ではなく.A < - ... 'を使用します。なぜなら、最終的に' .A() 'を呼び出す名前付き引数などを使ってより正式なコンストラクタを書くことが多いと思うからですライン。 –

+0

@MartinMorganありがとう、素敵なトリック!より正式なコンストラクタの例が '.A()'を使っているのを見て、それをなぜ '' new( "A") '? – cboettig

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) 

オブジェクトの構築をより透明にすることができます(第2の例では、newまたはBに無名の引数は継承されたクラスを初期化するために使用されているという事実を使用しています)。

ユーザが署名がちょうど...などであるため、例えば、直接.A又は.Bを使用する必要がすることは非常に友好的でない「は、クラスAのためのスロットの定義を参照」として記録されるであろう。これは、OOPの強みであるインタフェースと実装の分離を混乱させます。また、最後のコードチャンク(.B(.A(a=a), b=b)または.B(a=a, b=b))の1つまたは他の動作が意図されていない可能性があります。だからではなく、は、おそらくいくつかの初期データのマッサージ

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メソッドを不要にすることができます。これらはcomplicated contractをコピーコンストラクタとして初期化することになっています。上で見たように、名前のない引数は基本クラスを初期化することになっています)人々は間違っている。

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

関連する問題