【C++探索の旅】第一部分第八課:伝値引用、ファイルソース
1、第一部分第八課:値伝達引用、ファイルソース
2、第一部第九課予告:配列威武、動静合一
値参照、ファイルソース
この授業のタイトルはちょっと変です.実はこの授業のいくつかの重点内容を結びつけて取った名前で、ゆっくり勉強すればわかります.
前回の『【C++探索の旅】第1部第7課:関数効果、分而治之』では、関数を初歩的に認識しました.
しかし、あまり早く喜ばないでください.関数はこのようにあなたから遠ざかっていると思いますか.まさか、関数は一生を伴ってもいいですか.プログラミングを続けさえすれば.ははは、だからあなたは逃げられません~
[編集長、君と契約したんだから、薬を飲まないで勝手に出てぶらぶらしないでください]
この授業では、関数に関するいくつかの知識点を深く学び続けます.しかし、関数は私たちがずっと深く勉強して、後でクラス、オブジェクトなどのオブジェクト向けの知識があって、その時関数はまた1つの呼称を変えます.
値の転送と参照の転送
値の転送
まず、関数の範囲内でオペレーティングシステムがメモリをどのように管理しているかを学びます.
私たちの前のaddTwo関数を例に挙げます.この関数は簡単で、パラメータに2を加えて値を返します.次のようになります.
int addTwo(int a)
{
a += 2;
return a;
}
a+=2だと思っているのではないでしょうか.この一言はちょっと余計ですね.完全に直接return a+2;あ.次に、ここになぜこの文が追加されたのかがわかります.
この関数をテストするには、ウィジェットを書きます.
#include <iostream>
using namespace std;
int addTwo(int a)
{
a+=2;
return a;
}
int main()
{
int number(4), result;
result = addTwo(number);
cout << "number : " << number << endl;
cout << " : " << result << endl;
return 0;
}
このプログラムを実行し、出力:
numberの値は:4
関数を呼び出した結果は:6
プログラムの中で最も重要なのはもちろん
result = addTwo(number);
addTwo関数が呼び出されると、実際には多くのことが起こります.
重要な点は、変数numberがメモリの新しいアドレス(新しい引き出し)にコピーされ、この新しい引き出しのラベルがaです.パラメータaは値によって伝達される(numberの値がaにコピーされた)と言います.値伝達と呼ばれます.私たちのプログラムがaddTwo関数数にある場合、メモリの状況はほぼ下図のようになります.
そのため、メモリには3つの「引き出し」が使用されています.注意:number変数は変更されていません.
だからプログラムで変数aを操作するときはnumberとは関係なくnumberの値のコピーを操作するだけです.
リファレンス転送
私たちの前の授業では、引用(reference)の概念を初歩的に紹介しました.実はこの名詞を引用するのは抽象的すぎて、普通は初めて引用した友达に接触してすべて感じます:わあ、とても深い感じ.実は少しも深くなくて、引用はもっと正確に“別名”と呼ばれるべきです.
例えば、編集者は謝恩銘と呼ばれ、一部の人は小銘と戯れるかもしれない.その銘は私の別名です.この2つの名前は同じ人を指しているのではないでしょうか.はい、少しいたずらですが、プログラミング技術では決していい加減ではありません.
前述した値伝達の方式に加えて、変数numberの値を変数aにコピーする.
値伝達のほかに、他の方法もあります.メモリのnumberという引き出しにaというラベルを貼ることができます.number変数にaという別名を付けたのと同じです.関数のパラメータは参照を使用します.次のようになります.
int addTwo(int& a) // &
{
a+=2;
return a;
}
関数を呼び出すと、以前のような値のコピーはありません.プログラムはnumber変数に別名を与えただけです.私たちのプログラムがaddTwo関数にある場合、メモリの状況は大体下図のようになります.
今回、変数aと変数numberは同じメモリアドレス(同じ引き出し)を指し、引き出しに格納されている値は4であり、aとnumberはこの引き出しの2つの異なるラベルにすぎない.変数aは参照によって伝達され、参照伝達と呼ばれる.
参照は特に、上記の図から、メモリにはaという参照変数に新しいメモリアドレスが割り当てられていません.これは、参照されているnumberという変数のメモリアドレスを指しています.したがって、参照変数は、参照変数が指す変数のメモリアドレスと同じです.テストしてみましょう
#include <iostream>
using namespace std;
int main()
{
int number(4);
int &refNumber = number;
cout << "number : " << &number << endl;
cout << "refNumber : " << &refNumber << endl;
return 0;
}
実行、出力:
図に示すように、変数numberと参照変数refNumberのメモリアドレスはまったく同じです.
値伝達が問題を解決してくれる以上、なぜ参照伝達を使うのでしょうか.既生瑜は何が明るいですか.引用にはどんなメリットがありますか?
まず、上記の例から、リファレンスはメモリに新しいアドレスを開く必要がなく、コストを削減することがわかります.
C言語には引用の概念はありませんが、C++はあります.リファレンス伝達は、関数addTwoにパラメータを直接変更させることができます.以前のテストプログラムを引き続き使用しますが、今回は関数パラメータの参照です.
#include <iostream>
using namespace std;
int addTwo(int &a)
{
a+=2;
return a;
}
int main()
{
int number(4), result;
result = addTwo(number);
cout << "number : " << number << endl;
cout << " : " << result << endl;
return 0;
}
このプログラムを実行し、出力:
numberの値は:6
関数を呼び出した結果は:6
どうしてnumberの値が6になったのですか?以前の値伝達の例ではnumberの値は変わらなかった.
簡単です.前に言いましたが、引用は別名です.aはnumberの別名です.では、実際には同じメモリアドレスを指しているので、aに2を追加、つまりnumberに2を追加すると、numberの値が変わるのは当然です.
したがって、参照されるオブジェクトが変更されるため、参照の使用は慎重にしてください.
参照の使用の場合、古典的な例はswap関数であり、2つのパラメータの値を交換するために使用されます.
#include <iostream>
using namespace std;
void swap(double& a, double& b)
{
double temporary(a); // a temporary
a = b; // b a
b = temporary; // temporary b, a b
}
int main()
{
double a(2.3), b(5.4);
cout << "a " << a << " b " << b << endl;
swap(a,b); // swap
cout << "a " << a << " b " << b << endl;
return 0;
}
プログラムを実行し、出力:
aの値が2.3 bの値が5.4
aの値が5.4 bの値が2.3
aとbの2つの変数の値が交換されていることがわかります.
もし私たちが参照伝達ではなく、伝統的な値で伝達すれば、私たちが交換したのは変数のコピーだけで、変数自体ではありません.
しばらくは、引用の概念は皆さんに抽象的かもしれませんが、心配しないでください.私たちの後の授業ではよく引用を使います.引用についてはまだ言いたいことがたくさんあります.ゆっくりして、熟練して巧みになることができますか.
その後、ポインタの章を学び、引用とポインタの異同を説明します.
書き換え不可能なリファレンス転送
引用といえば、引用の慣用法を紹介する必要があります.この使い方は次の授業で役に立つので、まず奥を覗いてみましょう.
リファレンス転送は、値転送よりもコピーを行わないという利点があります.
関数がある場合、パラメータの1つがstringタイプの文字列であることを想定します.もしあなたのこの文字列変数の中の内容が長い文字列であれば、例えば小さな本ほど多くの文字があります.このような長い文字列をコピーするコストは、メモリでコピーしても時間がかかります.このようなコピーはまったく意味がないので、値の伝達方法を避ける必要があります.
もちろん、あなたは誇りに思って私に言います:私たちは引用で伝えることができます.はい、いい考えです.リファレンス伝達を使用すれば、コピーは不要です.ただし、リファレンス伝達には小さな欠陥があります.指向するオブジェクトを変更できます.しかしこれも欠陥とは言えないだろう.
void f1(string text); //
{
}
void f2(string& text); // , string
{
}
解決策は、書き換え不可能なリファレンス伝達を使用することです.
以前のレッスンではconstというキーワードを紹介しましたが、修飾された変数は変更できない変数になります.
リファレンスを使用してコピーを回避し、const変数でリファレンスを修飾すると、リファレンスを変更できなくなります.
void f1(string const& text); // , string
{
}
現在、この使い方は私たちにはあまり役に立たないようですが、このコースの第2部ではオブジェクト向けのプログラミングを学び、その時によく使われます.
ヘッダファイルとソースファイル、合理的な手配
前のレッスンで関数を説明したとき、関数は作成したレンガ(コードブロック)を再利用(再利用)するために使用されると述べました.
現在、カスタム関数の作成方法について学習していますが、これらの関数はmain関数と同じファイルに一時的に存在します.私たちはまだそれらを本当によく再利用していません.
C言語と同様に、C++はプログラムを異なるソースファイルに分割することもできます.これらのソースファイルでは、独自の関数を定義できます.
これらの関数を使用する場合は、ファイルの内容を導入し、これらの関数も導入します.これにより、私たちの関数は異なるプロジェクトで使用できます.これにより、分割されたレンガを本当に再利用して家を建てることができます.
必要書類
しかし、プログラムをよりよく組織するために、コンピュータの先駆者たちは、1つのファイルではなく2つのファイルを使用しました(なぜ「これ以上」勉強すればわかります):
(source file): .cpp ( .cc,.cxx,.C ), 。
(header file): .h ( .hxx,.hpp ), , (prototype)。
" " ? 。
addTwo , 。
int addTwo(int number)
{
int value(number + 2);
return value;
}
CodeBlocks IDE( ) 。 ( Vim,Emacs,Sublime, ) gcc( ) , 。
, Codeblocks C++ , main.cpp , 。
:
。
, :File > New > File。
C/C++ source:
, Go 。 :
C++, Next 。 :
( , )。 main.cpp 。
, 1.cpp, 。
math.cpp, addTwo , math(mathematics ) 。
Debug Release 。
Finish。 。 。
。 :File > New > File, C/C++ header:
Go :
, 。
main.cpp 。 MATH_H_INCLUDED , 。
Finish。 。
, :
, , 。
, 。 。
: 。
, , :
#include "math.h"
, 。
#include <iostream>
, C++ iostream( ) 。
,#include "math.h" math.h 。
, C++ , math.h ?
C++ ( ), include 。 #include < > , 。
, ( include ) 。
C++ , 。
,#include " " , include 。
math.cpp , , :
#include "math.h"
int addTwo(int number)
{
int value(number + 2);
return value;
}
,math.h 。 :
#ifndef MATH_H_INCLUDED
#define MATH_H_INCLUDED
#endif // MATH_H_INCLUDED
?
。 , 。
, 。 , :
#ifndef MATH_H_INCLUDED
#define MATH_H_INCLUDED
int addTwo(int number);
#endif // MATH_H_INCLUDED
# ?
。
, , , :
#ifndef MATH_H_INCLUDED
ifndef if not defined , " "。 : MATH_H_INCLUDED 。
,MATH_H_INCLUDED 。#ifndef MATH_H_INCLUDED 。
, #define MATH_H_INCLUDED, (define " " )MATH_H_INCLUDED
int addTwo(int number);
, :
#endif // MATH_H_INCLUDED
endif end if , " if ", // MATH_H_INCLUDED , 。
, , ,
#ifndef MATH_H_INCLUDED
MATH_H_INCLUDED, #ifndef MATH_H_INCLUDED 。 。 。
int addTwo(int number);
。 。
, CodeBlocks IDE, 。 , 。 。
MATH_H_INCLUDED , , 。
。 , , 。
, 。 string 。 , :
#ifndef MESSAGE_H_INCLUDED
#define MESSAGE_H_INCLUDED
#include <string>
void displayMessage(std::string message);
#endif // MESSAGE_H_INCLUDED
, #include <string> , string C++ 。 , ,string std::
?
cout,cin , std:: ?
cout,cin ,
using namespace std;
std ( , )。
cout cin std , std::
, using namespace std; ( using namespace std; , ), string std::, string std 。
, addTwo 。
main.cpp #include "math.h", math.h , math.cpp , math.cpp #include "math.h", main.cpp math.cpp 。( ...)
#include <iostream>
#include "math.h"
using namespace std;
int main()
{
int a(2), b(3);
cout << "a : " << a << endl;
cout << "b : " << b << endl;
b = addTwo(a); //
cout << "a : " << a << endl;
cout << "b : " << b << endl;
return 0;
}
, :
a : 2
b : 3
a : 2
b : 4
, 。 addTwo , math.h math.cpp 。 #include "math.h /math.h"
。 , , , , 。
, , 。
, , , , 。
, , 。 ( , ):
。 。 , ( " " )。
, :
addTwo :
#ifndef MATH_H_INCLUDED
#define MATH_H_INCLUDED
/*
* 2
* - number : 2
* : number + 2
*/
int addTwo(int number);
#endif // MATH_H_INCLUDED
。 (doxygen ):
/**
* \brief 2
* \param number 2
* \return number + 2
*/
int addTwo(int number);
, 。 , , 。
, 。 :
int secondNumber(int hours, int minutes, int seconds)
{
int total = 0;
total = hours * 60 * 60;
total += minutes * 60;
total += seconds;
return total;
}
, , , 。 。
, hours, minutes, seconds secondNumber 。 , 。
。
, 。 , 。
:
#include <iostream>
using namespace std;
//
int secondNumber(int hours, int minutes, int seconds);
//
int main()
{
cout << secondNumber(1, 10, 25) << endl;
return 0;
}
//
int secondNumber(int hours, int minutes, int seconds)
{
int total = 0;
total = hours * 60 * 60;
total += minutes * 60;
total += seconds;
return total;
}
, :
4225
1 3600 ,10 600 ,25 ... 25 。 3600 + 600 + 25 = 4225
, secondNumber 。 , minutes seconds 0, , 。
, :
int secondNumber(int hours, int minutes = 0, int seconds = 0);
? minutes seconds ,
= 0
。 0。 :
#include <iostream>
using namespace std;
//
int secondNumber(int hours, int minutes = 0, int seconds = 0);
//
int main()
{
cout << secondNumber(1) << endl;
return 0;
}
// ,
int secondNumber(int hours, int minutes, int seconds)
{
int total = 0;
total = hours * 60 * 60;
total += minutes * 60;
total += seconds;
return total;
}
, :
3600
hours 1, minutes seconds , 0。1 3600 。
: , , 。
:
cout << secondNumber(1,10) << endl;
:
4200
hours 1;minutes 10;seconds , 0
3600 + 600 = 4200
, , , ( secondNumber ):
1. hours seconds , minutes , ?
:
cout << secondNumber(1,,25) << endl;
。 C++ , , 。 , 。
:
cout << secondNumber(1, 0, 25) << endl;
2. ?
int secondNumber(int hours = 0, int minutes, int seconds);
, 。 。 , hours , hours , :
int secondNumber(int minutes, int seconds, int hours = 0);
。
3. ?
。 :
int secondNumber(int hours = 0, int minutes = 0, int seconds = 0);
cout << secondNumber() << endl;
0 。
。
。 。
( ), ( retur , 。
, 。 , :.cpp ,.h 。
。
, !
: ,