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

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

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

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

Q&A

解決済

2回答

939閲覧

クラスの宣言のデフォルト引数とは?(C++)

2BUT4

総合スコア14

C++

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

0グッド

0クリップ

投稿2017/11/17 16:23

【わからないこと】
・クラスの宣言で使う、デフォルト引数について

クラスの宣言部分のみ、記載します。(Base1クラス)

calss Base1{ protected: int bs1; public: Base1(int b1=0){bs1=b1}  //わからないところ void showBs1(); };

教えてほしいこと

・//コメントの行の(int b1=0)の部分がデフォルト引数、というもので、
「main関数でインスタンスが生成されたとき、引数としてもらった値に0が代入される」
という解釈で合っていますでしょうか?

・その後ろの{bs1=b1}の部分は、protectedのint bs1に引数としてもらった値を代入する、
という式の意味はわかるのですが、ブロックで囲まれているのはなぜでしょうか?


インスタンスが生成された(引数なしの場合)→b1に0が代入される→()の中が実行?→{}の中が実行?
インスタンスが生成された(引数ありの場合)→bs1にb1の値が代入される→{}の中が実行?


こんな風に勝手に考えたのですが、ちゃんとした意味を知りたいです。
よろしくおねがいします。

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

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

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

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

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

guest

回答2

0

あえて宣言と定義を分けて書くと

cpp

1calss Base1{ 2 3protected: 4 int bs1; 5public: 6 Base1(int b1 = 0); 7 8 void showBs1(); 9}; 10 11inline Base1::Base1(int b1){bs1=b1}

となる。コンストラクタと言っても実際のところ実行されるタイミングと呼び出される方法が違うだけで普通の関数となんら変わりない。

cpp

1Base1 base1;

というコードがあったとき、コンパイラはBase1クラスの宣言を見に行く。ユーザー定義のコンストラクタ(Base1(int b1=0){bs1=b1})があるのでデフォルトコンストラクタは自動生成されない。自動生成されるコピー/ムーブコンストラクタは適用できず唯一ユーザー定義のBase1(int b1=0){bs1=b1}が呼び出し可能であるので(引数0個でも呼び出せる)、そのコンストラクタが実行されるコードをコンパイラが吐く。

cpp

1Base1 base1{ 3 };

というコードが合った時を考える。この場合もほぼ同様の理由で唯一ユーザー定義のBase1(int b1=0){bs1=b1}が呼び出し可能であるので、そのコンストラクタが実行されるコードをコンパイラが吐く。

投稿2017/11/18 02:32

yumetodo

総合スコア5850

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

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

2BUT4

2017/11/18 06:38

yumetodoさん、回答ありがとうございます! 重ねて質問させてもらいたいのですが、Base1 base1{3}; というコードはBase1 base1(3);とは違う意味なのでしょうか。{}で囲んだ3は、(int b1=0)を飛び越えて、直接{bs1=b1}、つまりbs1に3を代入しているということですか? お時間ありましたら、返信いただけるとありがたいです。
yumetodo

2017/11/20 11:18 編集

回答遅れました。そういうことではありません。 C++11で追加されたuniform initializationという機能ですね。 基本的には()でも{}でも同じなんですが(std::initializer_listが絡まない限り)、{}のほうが、より統一的に初期化できるので、Templateと組み合わせる時ものすごく楽に書けます。あと関数呼び出しと曖昧にならないとか。 https://qiita.com/h2suzuki/items/d033679afde821d04af8
2BUT4

2017/11/20 15:30 編集

返信ありがとうございます! 親切に載せてくださったURLをさっそく見てみて、きっとわかりやすく書かれているはずなのに、基本も満足に出来ていない私には理解できることが少なく…(はじめのほうの配列や変数の初期化が{}で統一してできるということくらい。yumetodoさんが載せていたコードの{3}はこのことだとわかりました)ですが今回、こんなこともできるんだということを教えてもらえただけでもありがたいです! 学ばせていただきました!ありがとうございます。
yumetodo

2017/11/22 05:39

2015年のC++初心者Advent Calender https://adventar.org/calendars/922 ではかなり多くの記事でuniform initializationに言及があるので片っ端から読んでみるといいかもしれません。
guest

0

ベストアンサー

ええと、ちょっと難しく考えすぎですね。
こちらはわかりますか?ただのコンストラクタです。

C++

1calss Base1{ 2 3protected: 4 int bs1; 5public: 6 Base1(int b1) { 7 bs1 = b1; 8 } 9 void showBs1(); 10};

しかし、b1の値はほとんどのケースで一緒なので、省略したい。
省略できるようにする仕組みが、デフォルト引数です。

C++

1calss Base1{ 2 3protected: 4 int bs1; 5public: 6 Base1(int b1 = 0) { 7 bs1 = b1; 8 } 9 void showBs1(); 10};

ですので、実は置き換わっている部分は=0のところだけなんです。


クラスの宣言で使う、デフォルト引数について

デフォルト引数は関数やメソッド、コンストラクタで使えます。
クラスの宣言や定義の際に、特殊な何かが発動するわけではないです。

一番簡単な例だとこんな感じ。

C++

1#include <iostream> 2 3void hoge(int a = 0) { 4 std::cout << a << std::endl; 5} 6 7int main(void) { 8 hoge(1); 9 hoge(); 10 return 0; 11}

出力は1 (改行) 0 (改行)です。

「main関数でインスタンスが生成されたとき、引数としてもらった値に0が代入される」

という解釈

この場合「コンストラクタが呼び出されたとき、引数が省略されたら0として扱う」ですね。

その後ろの{bs1=b1}の部分は、protectedのint bs1に引数としてもらった値を代入する、

という式の意味はわかるのですが、ブロックで囲まれているのはなぜでしょうか?

潰して書いているからわかりづらいだけで、本当にただのブロックです。

インスタンスが生成された(引数なしの場合)→b1に0が代入される→()の中が実行?→{}の中が実行?
インスタンスが生成された(引数ありの場合)→bs1にb1の値が代入される→{}の中が実行?

コンストラクタが呼び出された → 引数が省略されたらb1を0とする → {}の中を実行

投稿2017/11/17 16:28

編集2017/11/17 16:34
LouiS0616

総合スコア35660

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

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

2BUT4

2017/11/18 06:33

LouiS0616さん、回答ありがとうございます! 簡単な例として書いてくださったコードで、わからなかったことが一気に解決しました。 コンストラクタが呼び出されたとき、{}の中の処理も同時に行われるのですね。 丁寧な説明、感謝します。この間に引き続き、本当にありがとうございました!
LouiS0616

2017/11/18 06:37

同時に行われると言うか、{}の部分でコンストラクタを実装しているのです。 ちょっと特殊な関数だと思っても実用上は問題ないかと思います。
2BUT4

2017/11/18 06:57

コンストラクタの定義を別で書かなくても、クラスの宣言でコンストラクタの{}の中に書いてあるから省略できてラク、ということでしょうか。つまり{}の中身が定義、ですか?
LouiS0616

2017/11/18 07:03

『中身が定義』という表現で正しいのかはちょっと微妙ですが、理解としては正しいと思います。 実際、次のようにしてコンストラクタの『宣言』のみを行うことも出来ます。 Base1(int bs1 = 0); この場合、プログラムの他の個所で実装する(定義する)必要があります。 ここらへんの事情は一般の関数と一緒です。
LouiS0616

2017/11/18 07:08

> 省略できてラク ラクと言えばラクですが、本質的にはちゃんと事情があります。 ヘッダファイルを書くようになるとわかると思いますが、定義はしないで宣言だけしたい場合があるのです。
2BUT4

2017/11/18 07:45

そうなのですね。。ヘッダファイル(<iostream>くらいしかわかりません…)など、もう少し調べてみて、また質問させてもらいたいと思います!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問