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

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

ただいまの
回答率

91.03%

  • C++

    2925questions

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

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

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 197

2BUT4

score 6

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

クラスの宣言部分のみ、記載します。(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の値が代入される→{}の中が実行?


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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

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

calss Base1{

protected:
    int bs1;
public:
    Base1(int b1) {
        bs1 = b1;
    }
    void showBs1();
};

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

calss Base1{

protected:
    int bs1;
public:
    Base1(int b1 = 0) {
        bs1 = b1;
    }
    void showBs1();
};

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


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

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

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

#include <iostream>

void hoge(int a = 0) {
    std::cout << a << std::endl;
}

int main(void) {
    hoge(1);
    hoge();
    return 0;
}

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

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

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

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

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

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/18 15:33

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

    キャンセル

  • 2017/11/18 15:37

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

    キャンセル

  • 2017/11/18 15:57

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

    キャンセル

  • 2017/11/18 16:03

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

    キャンセル

  • 2017/11/18 16:08

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

    キャンセル

  • 2017/11/18 16:45

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

    キャンセル

+1

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

calss Base1{

protected:
 int bs1;
public:
 Base1(int b1 = 0);

 void showBs1();
};

inline Base1::Base1(int b1){bs1=b1}

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

Base1 base1;

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

Base1 base1{ 3 };

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/18 15:38

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

    キャンセル

  • 2017/11/20 20:18 編集

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

    キャンセル

  • 2017/11/21 00:30 編集

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

    キャンセル

  • 2017/11/22 14:39

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

    キャンセル

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

  • ただいまの回答率 91.03%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C++

    2925questions

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