$ CC -c fact.cc # generates fact.o
$ CC factMain.o fact.o # generates factMain.exe or a.out
$ CC factMain.o fact.o -o main # generates main or main.exe
Сверьтесь с руководством пользователя вашего компилятора, чтобы уточнить, как именно компилировать и запускать программы, состоящие из нескольких файлов исходного кода.
Упражнение 6.9. Напишите собственные версии файлов fact.cc
и factMain.cc
. Эти файлы должны включать заголовок Chapter6.h
из упражнения предыдущего раздела. Используйте эти файлы чтобы понять, как ваш компилятор обеспечивает раздельную компиляцию.
Как уже упоминалось, при каждом вызове функции ее параметры создаются заново. Используемое для инициализации параметра значение предоставляет соответствующий аргумент, переданный при вызове.
Параметры инициализируются точно так же, как и обычные переменные.
Как и у любой другой переменной, взаимодействие параметра и его аргумента определяет тип параметра. Если параметр — ссылка (см. раздел 2.3.1), то параметр привязывается к своему аргументу. В противном случае, значение аргумента копируется.
Когда параметр — ссылка, говорят, что его аргумент
Когда значение аргумента копируется, параметр и аргумент — независимые объекты. Говорят, что такие аргументы
При инициализации переменной не ссылочного типа значение инициализатора копируется. Изменения значения переменной никак не влияют на инициализатор:
int n = 0; //
int i = n; //
i = 42; //
Передача аргумента по значению осуществляется точно так же; что бы функция не сделала с параметром, на аргумент это не повлияет. Например, в функции fact()
(см. раздел 6.1) происходит декремент параметра val
:
ret *= val--; //
Хотя функция fact()
изменила значение val
, это изменение никак не повлияло на переданный ей аргумент. Вызов fact(i)
не изменяет значение переменной i
.
Указатели (см. раздел 2.3.2) ведут себя, как любой не ссылочный тип. При копировании указателя его значение копируется. После создания копии получается два отдельных указателя. Однако указатель обеспечивает косвенный доступ к объекту, на который он указывает. Значение этого объекта можно изменить при помощи указателя (см. раздел 2.3.2):
int n = 0, i = 42;
int *p = &n, *q = &i //
*p = 42; //
p = q; //
//
То же поведение характерно для указателей, являющихся параметрами:
//
//
void reset(int *ip) {
*ip = 0; //
ip = 0; //
}
После вызова функции reset()
объект, на который указывает аргумент, будет обнулен, но сам аргумент-указатель не изменится:
int i = 42;
reset(&i); //
cout << "i = " << i << endl; //
Программисты, привыкшие к языку С, зачастую используют параметры в виде указателей для доступа к объектам вне функции. В языке С++ для этого обычно используют ссылочные параметры.
Упражнение 6.10. Напишите, используя указатели, функцию, меняющую значения двух целых чисел. Проверьте функцию, вызвав ее и отобразив измененные значения.