質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

6回答

1901閲覧

OOPでメンバー変数参照の不思議

matu

総合スコア17

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2015/12/16 15:21

編集2015/12/16 16:28

OOPで次のように、メンバー変数を直接するのと、メソッド経由で参照するのとで、値がことなります。
これの言語仕様がどういう理由によるものなのかが腑に落ちません。どのように考えたらよいのでしょうか。

なお、今回のサンプル記述はSystemVerilogというマイナーな言語(Java、C++をベースとしたハードウェア記述言語)になります。Rubyなど他の言語についても同じ動作となると想像されますが、詳しくはわかっていません。

verilog

1class Base; 2 int val=0; // public 3 virtual function int getval(); 4 return val; 5 endfunction 6endclass 7class Extend extends Base; 8 int val=1; // public 9endclass 10 11initial begin // main()に相当 12 Base b; 13 Extend e; 14 e = new(); 15 b = e; // downcast 16 $display("val is %d", b.val); // 0 17 $display("val is %d", b.getval()); // 1 18end 19

宜しくおねがいします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Stripe

2015/12/16 15:49

getval()の中に、return a;と書かれていますが?これは、return val;の間違い?
matu

2015/12/16 16:29 編集

はい、間違えました。修正しました。ありがとうございます
退会済みユーザー

退会済みユーザー

2015/12/16 21:13 編集

いや、C++/Java/Rubyともこんな挙動にならないと思います… 検索して出てきた http://www.eda.org/sv/SystemVerilog_3.1a.pdf の11.13節"Overridden members"に似た例が出てきています(ただしvirtual修飾子はついてない)。 これを読んでいると、何となく本当は例示コードのExtendクラスにもgetval関数が定義されてるのではないかと考えてしまうのですが、そうではないですか? あと、"b = e;"はダウンキャストではなくアップキャストです(よね?)。
matu

2015/12/17 12:30

言語仕様をチェックして下さり恐縮です。このサンプルコードではExtended ClassにBaseClassと全く同じgetval()を定義したのと同義になります。
退会済みユーザー

退会済みユーザー

2015/12/17 15:15

http://www.edaplayground.com/ で上記のコードを実行してみた(そのままでは動かなかったので、みようみまねでinitial begin〜end を module hoge〜endmoduleでくくりました)ところ、結果は2つとも0になりましたね… この挙動なら、他の言語に似ている、というかC++の(仮想)関数と全く同じなので説明はできるのですが…
guest

回答6

0

SystemVerilogは初めて知ったのですが、C++とC#について言えば、同じ動作とはなりません。
どちらかというと多分に言語仕様に関わる問題であって、OOPでひとくくりにはできないと思います。

ちなみに、C++やC#で同じようなことをすると、どちらも0になります。メンバ変数はオーバーライドできないので、Extendクラスのvalは、Baseクラスのvalとは別インスタンスになり、getvalメソッドはExtendでオーバーライドされない限り、常にBaseのvalを返します。

投稿2015/12/16 22:39

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

言語仕様上どうなっているかは知りませんが、以下の様にシミュレータはExtendの中に別々のvalがあると解釈をしていると考えられます。

Extendのメンバ

int val=0; // <-- Base member virtual function int getval(); // <-- Base member int val=1; // <-- Extend member

getval()の中では

int val=1; // <-- Extend member

の方を参照している一方でb.valは

int val=0; // <-- Base member

の方を参照していると考えられます。bのタイプがBaseだからでしょうか。e.valを表示するとどうなるんでしょうかね。言語仕様上曖昧なところはシミュレータ毎の解釈によって違ったりします。

この様な書き方が言語仕様上許されているのか分かりませんが、いずれにしても良い書き方ではないと思います。おそらく以下の様な事をしたかったのではないでしょうか。

SystemVerilog

1class Extend extends Base; 2 //---- Constructor ----// 3 function new(); 4 this.val = 1; 5 endfunction 6endclass

コンストラクタ関数new()でメンバ変数の初期化をします。この場合valは一つしかありませんのでどうvalを参照しようが値は同じです。

投稿2020/02/29 03:21

編集2020/02/29 03:49
vega77

総合スコア17

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

IEEE1800-2012で検索をすれば、言語仕様が無料でダウンロードできますよ。
8.20 virtual methodのexample 1が近い例になると思います。
Vitualをつけることで、基底クラス変数に派生クラスを代入しても、そのメソッドは派生クラスの結果を返してくれます。
イメージ的には、基底クラス用と派生クラス用それぞれにvalという変数が確保されていると考えるとわかりやすいかもです。
ただ、はまりやすい書き方だとは思うので、この様な書き方はしない方が良いかも知れないですね。

投稿2016/04/07 13:16

AtsushiHagiwara

総合スコア10

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

そもそもBaseクラスでgetVal()をvirtual(Javaのabstractに相当?)にしているのに本文記載してるし、
その上Baseがvirtualじゃないし、Extendでそれをオーバーライドしていないしで、
よくわからないコードになってます。
getVal()のvirtualを外してJavaで同等と思われるコーディングをしてみましたが、

java

1public class Q22748 { 2 3 public static void main(String[] args) { 4 Ext e = new Ext(); 5 Base b = e; 6 System.out.println(b.val); //0 7 System.out.println(b.getVal()); //0 8 9 } 10 11} 12 13class Base{ 14 int val = 0; 15 16 int getVal(){ 17 return val; 18 } 19} 20 21class Ext extends Base{ 22 int val = 1; 23} 24

値が変わるということはありませんでした。

投稿2015/12/17 01:53

swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

こんにちは。

SystemVerilogやVerilogを触ったことはありませんが、オブジェクト指向の考え方的に基底クラスのメソッドが派生クラスのメンバ変数をアクセスできるとは考えにくいです。
派生クラスのメンバ変数が基底クラスのそれと同じ意味であることは通常はあり得ないです。(同じ意味なら上書きする必要がないです) ですから、もしそれが出来るとかなり危険です。

従って、matuさんのコピペミスのように思えます。
Extendクラスにもgetval関数があるのではないでしょうか?

投稿2015/12/17 01:29

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

getval メソッドが返す a はどこに定義されてるんですか?
もしかして、virtual なら、メソッド内で参照される変数は架空のものでも良いという仕様でしょうか。
じゃなくて、virtual は、java で言うgeneric みたいなものか?,
a はテンプレートであり、 getvalの戻り値が int だから、派生クラスで定義したゆいいつのint 型変数に自動的に割ついた、って感じでしょうか。 fortran みたく、i,j,k は、でふぉるとで int 型、e,f,gは real型に割付くとか特殊ルールがありそうですね。

javaもc++も、基底クラスで、仮想関数:abstruct、virtual を定義して派生クラスで実装するとダウンキャストで仮想関数を呼び出すと派生クラスの実装が処理されます。
この言語は、基底クラスで側だけ定義しておいて、派生クラスで器だけ用意する仕組みなんでしょうか。

派生クラスでもう一個 int 型変数を定義したらコンパイルエラーになりそうなきがします。

投稿2015/12/16 16:36

ipadcaron

総合スコア1693

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問