1 Разное
Аргументы по умолчанию
В прототипах функций можно использовать аргументы по умолчанию:
void DrawCircle(int x=100,int y=100, int rad=200); // 1
void DrawCircle(int x,int y=100, int rad=200); // 2
void DrawCircle(int x,int y, int rad=200); // 3
В этом случае, вызов функции можно производить с меньшим числом фактических параметров. Остальные параметры примут значения по умолчанию, которые и будут переданы в функцию.
Примечание 1: Значения по умолчанию можно задавать для всех аргументов (функция 1).
Примечание 2: Задавать аргументы можно только в конце списка параметров (функции 1,2).
Вызовы можно осуществлять так:
- 1-ая функция:
- DrawCircle();
- DrawCircle(100);
- DrawCircle(100,600);
- DrawCircle(100,600,100);
- 2-ая функция:
- DrawCircle(100);
- DrawCircle(100,600);
- DrawCircle(100,600,100);
- 3-ая функция:
- DrawCircle(100,600);
- DrawCircle(100,600,100);
Доступ к глобальным переменным
Переменные могут быть объявлены как внутри блока (пары скобок { }), так и вне всех блоков. В первом случае такие переменные относят к локальным, а во втором - к глобальным. Что произойдет, если имена локальной и глобальной переменных совпадут?
В языках С/С++ такой случай приводит к ''сокрытию имени'', то есть локальное имя перекрывает внешнее. В С будет невозможно обратиться к глобальной переменной по имени, если такое же имя присвоено локальной переменной. В С++ для доступа к глобальной переменной используется операция :: (4 точки).
Оператор ::
int i=5;
int f()
{
int i=10;
i++; // локальное i теперь равно 11
::i++; // глобальное i теперь равно 6
}
Подставляемые функции
Когда компилятор встречает вызов функции он помещает в данную точку команды сохранения текущих значений регистров процессора и команду перехода по адресу, начиная с которого расположено тело функции. В общем случае это позволяет уменьшить итоговый размер программы за счет некоторого снижения ее быстродействия. Если тело функции очень мало (в С++ такие функции распространены), то данный эффект уменьшается и программа может терять как в быстродействии, так и в объеме.
Если описать функцию с ключевым словом inline, то ее тело будет помещено туда, где должен быть вызов, вместо того, чтобы помещать команды перехода.
Подставляемые функции
inline int f(int x)
{
....
};
2 Ссылки
- Альтернативное имя объекта
- Должна быть инициализирована
- Значение ссылки нельзя изменить
- Ни один оператор не выполняет действия над ссылкой
- Чаще всего используются для указания аргументов функции и возвращаемых значений
int i=1;
int& r1=i;
int& r2; // ошибка
int x = r1; // x = 1;
r1 = 2; // i = 2;
r1++; // i = 3;
int* pp = &r1; // pp указывает на i */
Инициализация
float f = 2.9;
double& dr1 = 1; // ошибка
double& dr2 = f; // ошибка
const double& cdr = 1;
void f (int val, int& ref) {
val++;
ref++;
}
void f2 () {
int i = 1, j = 1;
f (i, j); // i=1, j=2
}
Аргументы функции
double sqrt (const double&);
void f1 (double d) {
float f = sqrt(1);
f = sqrt(f);
f = sqrt(d);
}
void update (float&);
void f3 (double d, float f) {
update(2.0f); //ошибка
update(f);
update(d); //ошибка
}
Возвращаемые значения
int& fr1(int i) {
int local = 0;
local+=i;
return local; // плохо
}
int& fr2(int i) {
static int local_st = 0;
local_st+=i;
return local_st; // хорошо
}
int* fp(int i) {
int local = 1;
local+=i;
return &local; // плохо
}
3 Перезрузка функций
Перегруженные имена функций
void print(int);
void print(const char*);
void print(double);
void print(long);
void print(char);
int h(char c, int i, short s, float f) {
print(c); // print(char)
print(i); // print(int)
print(s); // print(int)
print(f); // print(double)
print(‘a’); // print(char)
print(49); // print(int)
print(0); // print(int)
print("a"); // print(const char*)
}
Возвращаемые типы
возвращаемые типы не участвуют в разрешении перегрузок
float sqrt(float);
double sqrt(double);
void f(double da, float fla)
{
float fl = sqrt(da); // вызов sqrt(double)
double d = sqrt(da); // вызов sqrt(double)
fl = sqrt(fla); // вызов sqrt(float)
d = sqrt(fla); // вызов sqrt(float)
}
Явное разрешение
void print(char);
void print(long);
void g(int i) {
print(i); // ошибка
}
void pow(int, int);
void pow(double, double);
void k(char c, float f) {
pow (2, 2);
pow (2.0, 2.0);
pow (2, c);
pow (f, 2.0);
pow (2.0, 2); // ошибка
}
Динамическая память
В языке С для работы с динамической памятью служит набор функций стандартной библиотеки alloc. В С++ выделение и освобождение памяти выполняется на уровне операторов языка (new, delete) и в более простом виде:
Выделение и освобождение памяти
int *a=new int;
int *b=new int[20];
delete a;
delete [] b;
Использование new для экземпляров классов влечет за собой:
- вызов конструктора
- выделение памяти
Использование delete для экземпляров классов влечет за собой:
- вызов деструктора
- освобождение памяти