Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

Перезагрузка конструкторов

Как и методы, конструкторы также могут перегружаться. Это дает возможность конструировать объекты самыми разными способами.

Одна из самых распространенных причин для перегрузки конструкторов заключается в необходимости предоставить возможность одним объектам инициализировать другие.

Когда приходится работать с перегружаемыми конструкторами, то иногда очень полезно предоставить возможность одному конструктору вызывать другой. В C# это дается с помощью ключевого слова this. Ниже приведена общая форма такого вызова:

имя_конструктора(список_параметров1): this(список_параметров2)

{

//... Тело конструктора, которое может быть пустым.

}

В исходном конструкторе сначала выполняется перегружаемый конструктор, список параметров которого соответствует критериюсписок_параметров2, а затем все остальные операторы, если таковые имеются в исходном конструкторе. Ниже приведен соответствующий пример:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace ConsoleApplication1

{

class UserInfo

{

public string Name, Family;

public byte Age;

 

// Используем ключевое слово this для

// создания "цепочки" конструкторов

public UserInfo(): this("None","None",0)

{

}

 

public UserInfo(UserInfo obj)

: this(obj.Name, obj.Family, obj.Age)

{

}

 

public UserInfo(string Name, string Family, byte Age)

{

this.Name = Name;

this.Family = Family;

this.Age = Age;

}

}

 

class Program

{

static void Main(string[] args)

{

UserInfo ui1 = new UserInfo();

Console.WriteLine("ui1: {0}, {1}, {2}",ui1.Name,ui1.Family,ui1.Age);

 

UserInfo ui2 = new UserInfo("Alex","Erohin",26);

Console.WriteLine("ui2: {0}, {1}, {2}", ui2.Name, ui2.Family, ui2.Age);

 

UserInfo ui3 = new UserInfo(ui2);

Console.WriteLine("ui3: {0}, {1}, {2}", ui3.Name, ui3.Family, ui3.Age);

 

Console.ReadLine();

}

}

}

Перегрузка функций (методов класса). Создание и использование конструкторов копирования. Устаревшее ключевое слово overload. Перегрузка и неоднозначность. Ключевое СЛОВО explicit. Определение адреса перегруженной функции. Перегрузка методов класса. Пример

Перегрузка функций – это свойство полиморфизма ОПП. Это требует обязательного выполнения требования к перегружаемым функциям – имена функций должны быть одинаковыми.

Обратите внимание: Методы также называются функциями.

Методы классов, так же как и обычные функции C++, можно перегружать. Перегрузка функций означает, что в текущей области действия одно и то же имя могут использовать несколько функций. Компилятор выбирает нужную функцию, учитывая количество и тип аргументов, использованных при ее вызове. Пример иллюстрирует перегрузку метода, названного number (). Перегружаемая функция возвращает абсолютное значение чисел типа int или double, используя математическую функцию abs(), принимающую и возвращающую значения int, и функцию fabs(), которая принимает и возвращает значения типа double. При перегрузке функции тип аргумента определяет, какой метод класса на самом деле используется.

//#include "stdafx.h"

#include <iostream>

#include <tchar.h>

#include <math.h>

using namespace std;

 

class absolute_value

{

public:

int number(int);

double number(double);

};

 

int absolute_value::number(int test_data)

{

int answer;

answer=abs(test_data);

return(answer);

}

 

double absolute_value::number(double test_data)

{

double answer;

answer=fabs(test_data);

return(answer);

}

 

int _tmain(int argc, _TCHAR* argv[])

 

{

absolute_value neg_number;

cout << "The absolute value is "

<< neg_number.number(-583) << endl; // Абсолютное значение равно...

cout << "The absolute value is "

<< neg_number.number(-583.1749) << endl;

return 0;

}

Создание и использование конструкторов копирования.

По умолчанию при инициализации одного объекта другим С++ выполняет побитовое копирование. Это означает, что точная копия инициализирующего объекта создается в целевом объекте. Хотя в большинстве случаев такой способ инициализации объекта является вполне приемлемым, имеются случаи, когда побитовое копирование не может использоваться. Например, такая ситуация имеет место, когда объект выделяет память при своем создании. Рассмотрим в качестве примера два объекта А и В класса ClassType, выделяющего память при создании объекта. Положим, что объект А уже существует. Это означает, что объект A уже выделил память. Далее предположим, что А использовался для инициализации объекта B, как показано ниже:

ClassType В = А;

Если в данном случае используется побитовое копирование, то В станет точной копией А. Это означает, что В будет использовать тот же самый участок выделенной памяти, что и A, вместо того, чтобы выделить свой собственный. Ясно, что такая ситуация нежелательна. Например, если класс ClassType включает в себя деструктор, освобождающий память, то тогда одна и та же память будет освобождаться дважды при уничтожении объектов A и B!

Проблема того же типа может возникнуть еще в двух случаях. Первый из них возникает, когда копия объекта создается при передаче в функцию объекта в качестве аргумента. Второй случай возникает, когда временный объект создается функцией, возвращающей объект в качестве своего значения. (Не надо забывать, что временные объекты автоматически создаются, чтобы содержать возвращаемое значение функции, и они могут также создаваться в некоторых других ситуациях.)

Для решения подобных проблем язык С++ позволяет создать конструктор копирования, кото­рый используется компилятором, когда один объект инициализирует другой. При наличии кон­структора копирования побитовое копирование не выполняется. Общая форма конструктора копирования имеет вид:

имя_класса (const имя_класса &о) {

// тело конструктора

}

Здесь о является ссылкой на объект в правой части инициализации. Конструктор копирования может иметь также дополнительные параметры, если для них определены значения по умолчанию. Однако в любом случае первым параметром должна быть ссылка на объект, выполняющий инициализацию.

#include <iostream.h>

#include <stdlib.h>

class array {

int *p;

int size;

public:

array(int sz) {

p = new int[sz];

if (!p) exit(1);

size = sz;

}

~array() {delete [] p; }

// конструктор копирования

array(const array &a);

void put(int i, int j) {

if (i>=0 && i<size) p[i] = j;

}

int get (int i) {

return p[i];

}

};

Устаревшее ключевое слово overload.

Первые компиляторы С для перегрузки функции использовали синтаксис:

overload <имя_функции>;

Перегружаемая функция должна быть описана до overload.

Современные компиляторы не требуют применения overload, но их применение не вызывает ошибку.

Перегрузка и неоднозначность.

При перегрузке возможно внесение неоднозначности в программу. Неоднозначность, вызванная перегрузкой функций, может быть введена в программу при преобразовании типа, а также при использовании параметров-ссылок и аргументов по умолчанию. Некоторые виды неоднозначности вызываются самой перегрузкой функций. Другие виды связаны со способом вызова перегруженных функций. Чтобы программа компилировалась без ошибок, от неоднозначности необходимо избавиться.

Ключевое СЛОВО explicit.

Ключевое слово explicit используется для создания «неконвертирующих конструкторов» (nonconverting constractors). Например, рассмотрим следующий класс:

class MyClass {

int i;

public:

MyClass(int j) {i = j;}

//...

};

Объекты этого класса могут быть объявлены следующим образом:

MyClass ob1(1);

MyClass ob2 = 10;

В данном случае инструкция

MyClass ob2 = 10;

автоматически конвертируется в следующую форму:

MyClass ob2(10);

Однако, если объявить конструктор MyClass с ключевым словом explicit, это автоматическое конвертирование не будет выполняться. Ниже объявление класса MyClass показано с использованием ключевого слова explicit при объявлении конструктора:

class MyClass {

int i;

public:

explicit MyClass(int j) {i = j;}

//...

};

Теперь допустимыми являются только конструкции следующего вида:

MyClass ob (110);

Замечание: Конструктор, использующий explicit не применяет участие в образовании типа. Вывод: есть смысл применять, если тип не преобразуется.

Определение адреса перегруженной функции.

Для определения адреса функции используется синтаксис:

//Первая версия функции

int Func(int i, int j);

int Func (long l); //Вторая версия функции

//Определение адреса первой версии функции

int (*pFunc)(int, int)=Func;

//Вызов функции

pFunc(10,20);


Дата добавления: 2015-09-03; просмотров: 187 | Нарушение авторских прав


Читайте в этой же книге: Перегрузка операций (операторов). Перегрузка операторов отношения и логических операторов. Перегрузка оператора присваивания. Перегрузка унарных операторов. | Перегрузка операций (операторов). Перегрузка операторов инкремента и декремента. Перегрузка оператора индексирования. Перегрузка оператора вызова функции. | Перегрузка операций (операторов). Перегрузка операторов доступа к членам класса. Перегрузка операторов new и delete. Функции преобразования типа. | Полиморфизм и виртуальные функции. Раннее и позднее связывание. Динамический полиморфизм. Виртуальные функции. Виртуальные и невиртуальные функции. | Полиморфизм и виртуальные функции. Применение динамического полиморфизма. Виртуальные деструкторы. Абстрактные классы и чисто виртуальные функции. | Длина самого длинного слова 10 | Самое длинное слово beautiful | Строковые потоки | Состояние формата (ОТНОСИТСЯ К ПОСЛЕДНЕМУ ВОПРОСУ, КОТОРЫЙ 24) | Работа с несовместимыми конструкциями. |
<== предыдущая страница | следующая страница ==>
Неполный конструктор| Перегрузка операций (операторов). Понятие перегрузки операторов. Синтаксис перегрузки операции. Перегрузка бинарных операторов.

mybiblioteka.su - 2015-2024 год. (0.014 сек.)