C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

親クラスとインナークラスの関係

[トピック内 16 記事 (1 - 16 表示)]  << 0 >>

■91330 / inTopicNo.1)  親クラスとインナークラスの関係
  
□投稿者/ ぷら (8回)-(2019/06/17(Mon) 00:56:18)

分類:[C/C++] 

重ね重ね、質問でごめんなさい!

C++の勉強を進めていく中で気になったのが、classの中のclass(インナークラス)についてです。
インナークラスから親クラスのメンバ変数を操作するための方法について、下記のサイトを参考にしましたが上手くいきませんでした。

(参考サイト)http://d.hatena.ne.jp/Nilfs/20111204/1323015742


||||||||||||||||||||||||||||||||||||||||||||||||
// テストプログラム


class HOGE{
int i_hoge;

class INNER_HOGE{
public: Hoge(const HOGE& hoge)

};
};

int main(){
HOGE hoge;
HOGE::INNER_HOGE Hoge(hoge);
}


||||||||||||||||||||||||||||||||||||||||||||||||
// コンパイルエラー内容

コンストラクター "HOGE::INNER_HOGE::Hoge" のインスタンスが引数リストと一致しません

||||||||||||||||||||||||||||||||||||||||||||||||

こういった場合はどうするんですか?
また、インナークラスからは親クラスを見ることが出来るが、親クラスからはインナークラスは見れないようになっているという認識で合ってますか?
引用返信 編集キー/
■91333 / inTopicNo.2)  Re[1]: 親クラスとインナークラスの関係
□投稿者/ Azulean (1066回)-(2019/06/17(Mon) 06:38:18)
No91330 (ぷら さん) に返信
> C++の勉強を進めていく中で気になったのが、classの中のclass(インナークラス)についてです。
> インナークラスから親クラスのメンバ変数を操作するための方法について、下記のサイトを参考にしましたが上手くいきませんでした。

サイトとよく見比べてください。
INNER_HOGE の中で、コンストラクタではなく、Hoge というメンバー関数を作ってしまっています。
結果として、コンストラクタは引数なしのデフォルトコンストラクタしかありませんので、引数をつけた呼ぶコードが見つかってエラーになっています。
引用返信 編集キー/
■91334 / inTopicNo.3)  Re[2]: 親クラスとインナークラスの関係
□投稿者/ 774RR (701回)-(2019/06/17(Mon) 07:10:49)
リンク先は「他人に見せない関数オブジェクト」の話をしてるけど、それは古い C++ 限定の話。
C++11 以後は lambda 式っつのが書けるようになっているので、
関数オブジェクトのためだけのインナークラスってのは不要になってきている。

便利なんだけど、ではいつでもどこでも C++11 や C++14 が使えるかというとそんなこともなくて以下略

引用返信 編集キー/
■91338 / inTopicNo.4)  Re[2]: 親クラスとインナークラスの関係
□投稿者/ ぷら (9回)-(2019/06/17(Mon) 10:59:28)
No91333 (Azulean さん) に返信
> サイトとよく見比べてください。
> INNER_HOGE の中で、コンストラクタではなく、Hoge というメンバー関数を作ってしまっています。
> 結果として、コンストラクタは引数なしのデフォルトコンストラクタしかありませんので、引数をつけた呼ぶコードが見つかってエラーになっています。

サイトでは、
Hoge::InnerClass innerClass(hoge);
とあり、関数の先頭が小文字なのでデフォルトコンストラクタではないものと思っていました。
引用返信 編集キー/
■91339 / inTopicNo.5)  Re[3]: 親クラスとインナークラスの関係
□投稿者/ ぷら (10回)-(2019/06/17(Mon) 11:08:31)
2019/06/17(Mon) 11:19:43 編集(投稿者)

No91334 (774RR さん) に返信
> リンク先は「他人に見せない関数オブジェクト」の話をしてるけど、それは古い C++ 限定の話。
> C++11 以後は lambda 式っつのが書けるようになっているので、
> 関数オブジェクトのためだけのインナークラスってのは不要になってきている。
>
> 便利なんだけど、ではいつでもどこでも C++11 や C++14 が使えるかというとそんなこともなくて以下略
>


いつも勉強になります。

ただ、私自身は「他人に見せない関数オブジェクト」を作ることを目的にしているというよりは、
インナークラスによる、クラスよりも狭い範囲で共通変数を作ることができるのかなと思った次第です。


イメージでは、インナークラスが大きな1つの関数で、
親クラスのメンバー変数をグローバル変数みたいに扱えないかなぁって思いました。

サイト通りに色々やってみたけど、
E0137 式は変更可能な左辺値である必要があります
ってどのみちエラーが出て怒られてしまうので参照はできても変更はできなそうでした!


特に他にコレといった目的はなく、前回の質問でメモリに関することをさせて頂いたので、
インナークラスが終了すれば、そのインナークラスのメンバー変数などによるメモリ確保してた部分は
解放されるのかなぁと個人的に予想してたり…。

でも、この方法だと、
main関数内に、インナークラスのオブジェクト作らない形ですし親クラスと同時に解放されるので意味ない…?(´;ω;`)ウゥゥ
引用返信 編集キー/
■91341 / inTopicNo.6)  Re[3]: 親クラスとインナークラスの関係
□投稿者/ 774RR (702回)-(2019/06/17(Mon) 12:56:12)
C++ において、変数の「可視性=スコープ」と「寿命=記憶域期間」は、クラス定義とは無関係

> インナークラスが大きな1つの関数で、
なんてことは無いっす。

> クラスよりも狭い範囲で共通変数を作る
ってのが具体的に何を期待しているのかオイラには想像つかないんだけど、それはたぶん
「インナークラス」とやらで実現するものでは*ない*と思われるっす。

例示例では Hoge::InnerClass という名前のクラスがあるってだけ。それは他の型と対等で
int や Hoge や basic_string なんかと扱いは同じ。だから

> class InnerClass {
> InnerClass(const Hoge& hoge) // は InnerClass::InnerClass でコンストラクタだし
> Hoge::InnerClass innerClass(hoge); // は InnerClass 型の変数 innerClass を作ってる

ってことで。


引用返信 編集キー/
■91345 / inTopicNo.7)  Re[4]: 親クラスとインナークラスの関係
□投稿者/ ぷら (11回)-(2019/06/17(Mon) 19:45:34)
No91341 (774RR さん) に返信
> C++ において、変数の「可視性=スコープ」と「寿命=記憶域期間」は、クラス定義とは無関係

勘違いされてるかもしれませんが、クラス定義に関する質問というよりは、
実際にクラスのインスタンス変数を宣言してクラスを使うときに使用する
メモリの確保量を節約する方法を質問させていただいている次第です。

クラスのインスタンス変数を宣言した関数が終了すれば、
デストラクタが呼び出されて、メンバー変数などが破棄されるものと認識しています。


~~~~~~~~~


>>インナークラスが大きな1つの関数で、
> なんてことは無いっす。

"みたいに扱えないかなぁって"って申し上げた通り、イメージの例えなのですが…。
関数が終わればローカル変数が破棄されるという感じのノリで、インナークラスのメンバ変数を破棄しちゃいたいみたいな。


~~~~~~~~~~~~~~~~~~~~~~~~

>
>>クラスよりも狭い範囲で共通変数を作る
> ってのが具体的に何を期待しているのかオイラには想像つかないんだけど、それはたぶん
> 「インナークラス」とやらで実現するものでは*ない*と思われるっす。


具体的には、プログラムにある関数すべてを100%としたとき。
AとBとCと…などの変数n個を使う関数が、全体の5%あり、その関数間では共通して使用したい。
(その5%の関数が、20%のメンバ関数があるクラスの1つのメンバ関数だったとき)

グローバル変数で変数を記述するにしては広すぎる、
クラス内のメンバー変数と使うにしてもやや広すぎる、
かといって関数のローカル変数として宣言するにはやや無理がある。

といったシチュエーションを想定しています。
何か方法があるんですかね?


~~~~~~~~~~~~~~~~~~~~~~~

> 例示例では Hoge::InnerClass という名前のクラスがあるってだけ。それは他の型と対等で
> int や Hoge や basic_string なんかと扱いは同じ。だから
>
>>class InnerClass {
>> InnerClass(const Hoge& hoge) // は InnerClass::InnerClass でコンストラクタだし
>>Hoge::InnerClass innerClass(hoge); // は InnerClass 型の変数 innerClass を作ってる
>
> ってことで。

対等ですよね?
ってことは、A関数でインナークラスのインスタンス変数を宣言したとき、
A関数が終わればインスタンス変数とともにそのメンバー変数の中身などが破棄されるのでは?

staticとかついてない限りはint型などの変数だって、関数が終われば中身消えるでしょ?

引用返信 編集キー/
■91347 / inTopicNo.8)  Re[5]: 親クラスとインナークラスの関係
□投稿者/ 774RR (703回)-(2019/06/17(Mon) 21:59:51)
自動変数なら関数(というかブロック)が終わる時に一緒に寿命が尽きます。
ってことで「関数を超えて共用」するには static (大域変数っつか静的記憶域期間変数)しかないです。
そしてそんなことをするとマルチスレッドで安全でなくなります。
「関数を超えて共用」というのがどういう発想なのかわかりませんが、
通常はそういうことをしない、そもそも共有するというのは発想レベルでおかしい、スレッド安全でない
ってあたりから思考そのものを変えていくしかないです。

大域変数であっても class スコープにあれば private / protected アクセス対象になるわけで、
アクセスできないところからはアクセスできない、つまり可視性の面では安全です。
排他しなきゃならないあたりでは全く持って安全ではないです。

---

class hoge_type {
    std::ifstream infile;
public:
    hoge_type(const std::string& fn) { /* infile を開く */ }
    int read_int(...) { /* infile から読む */ }
    double read_long(...) { /* infile から読む */ }
    ~hoge_type() { /* infile を閉じて破棄する */ }
};

なんてのであれば「関数を超えて共用」っぽく使うことはできるでしょう。

引用返信 編集キー/
■91349 / inTopicNo.9)  Re[6]: 親クラスとインナークラスの関係
□投稿者/ ぷら (12回)-(2019/06/17(Mon) 23:45:04)
2019/06/17(Mon) 23:52:22 編集(投稿者)

No91347 (774RR さん) に返信
> 「関数を超えて共用」というのがどういう発想なのかわかりませんが、
> 通常はそういうことをしない、そもそも共有するというのは発想レベルでおかしい、スレッド安全でない
> ってあたりから思考そのものを変えていくしかないです。

そもそも、クラスのメンバー変数は共有じゃないんですか?
そこが疑問なんですけど…?

それ言ったら、グローバル変数はどうなるんでしょうか?


この方法を使うのは良くないですかね…??
https://hwada.hatenablog.com/entry/20051006/1128549188
引用返信 編集キー/
■91351 / inTopicNo.10)  Re[7]: 親クラスとインナークラスの関係
□投稿者/ 774RR (704回)-(2019/06/18(Tue) 06:53:34)
どうもオイラとぷら氏の間で認識違いがあるようだ。
ぷら氏がいう「共用」「共有」がどういうことなのかオイラにはわかっていないので話が通じん。

int main(int argc, char* argv[]) {
    myfunc();
}

のようなコードがあるとして myfunc() の中で argc や argv を使いたい=共有したい、のであるならば
( myfunc() に引数で引き渡されていないという現状において)
それはバグの元だからできない。できないように言語仕様自体が設計されているわけで、できてはならない。

struct mycomplex {
    double re;
    double im;
    double arg() { return atan2(re, im); }
    double square() { return re*re+ im*im; }
    double abs() { return sqrt(square()); }
};
であれば mycomplex のインスタンスが生きている限りにおいて arg() と square() が同じ値 re im を
使うことが出来る、それはある意味「共有している」と言えるだろう。実のところ共有なんかしてないけど。

提示リンクは関数内関数の例だけど、今なら lambda のほうがはっきりくっきり楽。

引用返信 編集キー/
■91353 / inTopicNo.11)  Re[8]: 親クラスとインナークラスの関係
□投稿者/ ぷら (13回)-(2019/06/18(Tue) 10:42:25)
2019/06/18(Tue) 13:57:52 編集(投稿者)

No91351 (774RR さん) に返信
> どうもオイラとぷら氏の間で認識違いがあるようだ。
> ぷら氏がいう「共用」「共有」がどういうことなのかオイラにはわかっていないので話が通じん。

私が考えていた共有は、終了するブロックがきたら関数の変数が解放されるという性質を利用したいが、
複数の関数間の処理が終わるまで同一の変数を使いたいので、それらの関数をまとめた関数があればいいなと思っていました。


→これは関数内にclassを配置、または、lambdaで解決できる ということですね。ありがとうございます。
しかし、この方法だと classの外にある関数内のローカル変数を使用することはできませんよね。

そういった場合はポインタ渡しで渡してあげるしかないのでしょうか?

下記のようなプログラムを書いているうちに、効率の悪いプログラムというか、そんな書き方してまで使う用途なんて無さそうと思ってしまいました。
でも、興味本位といいますか、実現可能なのかどうか知りたいので教えていただけますでしょうか。

やればやるほど分からなくなっていきます。
774RRさまの知識を拝借させてください!


-----------------------------

void Hoge(){

vector <vector<int>> hoge{30, vector<int>(3, 0)};

class HOGE{
int a;
int b;
vector <vector<int>> *h;

HOGE(vector <vector<int>> &hoge){ //アドレスで受け取る
*hoge = &hoge;           //アドレスをコピーしてクラス内で使えるようにする
}

void A(){
a = a+a;
}

void B(){
b= a+b;
}

void C(){
*h.capacity().reserve(*h.size()); //これやるとどうなる?
}

};

HOGE *hogeeeee = new HOGE(hoge);
hogeeeee->C();
delete hogeeeee;

…まだプログラムが続くと想定した場合にはnewで確保してdeleteして解放してあげたほうがいい?…

}
引用返信 編集キー/
■91354 / inTopicNo.12)  Re[9]: 親クラスとインナークラスの関係
□投稿者/ 774RR (705回)-(2019/06/18(Tue) 11:43:55)
提示コードはポインタ回りが致命的にバグっているのでなにがしたいのか余計にわからない。
そもそも vector.capacity() < vector.size() になることはありえないし。

> 終了するブロックがきたら関数の変数が解放されるという性質を利用したいが、
ここは極めて理解できる。なのに new/delete を手書きしているのは減点。

> 同一の変数を使いたいので、それらの関数をまとめた関数があればいいな
関数(ラムダ式)を複数個、ひとつの関数の中でまとめて作る、なら可能っす。

> 関数内のローカル変数を使用することはできませんよね。
フツーにラムダ式で関数内変数をキャプチャして使うことはできるよ。

int main()
{
	std::vector<int> v(10);
	auto set = [&v](int index, int val) { v[index] = val; };
	auto get = [&v](int index) { return v[index]; };
	set(0, 1 + 2);
	std::cout << get(0) << std::endl;
}


引用返信 編集キー/
■91357 / inTopicNo.13)  Re[10]: 親クラスとインナークラスの関係
□投稿者/ ぷら (14回)-(2019/06/18(Tue) 14:05:34)
No91354 (774RR さん) に返信
ごめんなさい、自分が何をしたいのかも分からなくなってきました。

ラムダ式でなくクラスを用いて実現してみたいと思ったのですが、無理あるようですね。
一度、ラムダ式について勉強をしてみたいと思います。
引用返信 編集キー/
■91359 / inTopicNo.14)  Re[11]: 親クラスとインナークラスの関係
□投稿者/ 774RR (706回)-(2019/06/18(Tue) 14:52:01)
およそ C++ を始めとするいろんな言語において新しい機能を追加する際には、
人間から見ると新しい機構なんだけど、コンパイラ(の実装者)的には既にある機能をラップしただけ
なんてのがよくあって、このラムダ式もそう。
ラムダ式はコンパイラ内部では無名な使い捨てクラスの operator() として実装されているわけで、
まさに関数内クラスを使っているわけだ。

そういう意味で関数内クラスってのは勉強する価値はある、んだけど
ラムダ式のほうが覚える必要のある内容が少ないし、手書き量は少ないし、ってことで
今更関数内クラスをバンバン手書きするよりはラムダ式書けるようになるほうがお役立ちだと思う。

引用返信 編集キー/
■91360 / inTopicNo.15)  Re[11]: 親クラスとインナークラスの関係
□投稿者/ ぷら (15回)-(2019/06/18(Tue) 14:54:34)
よく考えてみたら、ポインタ渡しが出来ない、バグるというのなら、下記の方法でも行けるんじゃないですかね?
もはやクラスとしての役割、意義を見失いかけていますが…。(ラムダ式を使わない場合に考えられる方法を考えました)

しかし、func()やhoge1()やhoge2()の引数に全部、A aを渡していますが、
これって実体がメモリ上にコピーされるということになり、結果的にメモリを圧迫する原因になりかねないですよね…?

ーーーーーーーー

class A{
int x;
int y;
int z;
};


class B{
int c;
int d;

void hoge1(A a){
d = a.y + a.z + c;
}

void hoge2(A a){
c = a.x + d;
hoge1(a);
}

};


void func(A a){
int f = 100;
a.x = a.x + f;
B b;
b.hoge(a)
} //Aここでbは消えるがaは残る


int Set(){
int e = 10;
A a;
a.x= e;
func(a); //@hoge1()とhoge2()の共用変数を作るためにB bを宣言したいが、func関数が終われば共用変数には用無しで無駄なので、fanc関数内で宣言する

…まだまだA aのメンバを用いた処理をする…

}//Bここでaが消える


int main(){
Set(); //Set()やfunc()やclass Bの共用変数を作るためにA aを宣言したいが、Set関数が終われば共用変数には用無しで無駄なので、Set関数内で宣言する

…他の処理をする…

}
引用返信 編集キー/
■91361 / inTopicNo.16)  Re[12]: 親クラスとインナークラスの関係
□投稿者/ 774RR (707回)-(2019/06/18(Tue) 15:22:30)
うーん。

「本当にしたいこと」が提示コードから伝わってこないのは XY 問題ってやつ?あるいは青年とラクダ?
https://ja.meta.stackoverflow.com/questions/2701/

単純に提示コードに関して技術論を述べるとするなら
B::hoge1() も B::hoge2() も a の複写を受け取って、複写は B::hoge1() 終了時に破棄されるので
効率面では全然おいしくないから B::hoge1(const A& a) { ... } のほうがマシ。

でもこういうアプローチを推し進めても「本当にしたいこと」には近づかないかもしれない。
少なくともオイラはこういう書き方しないだろう(絶対に、をつけてもいい)

お互い、ちょっと頭冷やそうか。
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ