Как использовать другой класс в c
Перейти к содержимому

Как использовать другой класс в c

  • автор:

Объявления вложенных классов

Класс можно объявить в области другого класса. Такой класс называется вложенным классом. Вложенные классы считаются в пределах область включаемого класса и доступны для использования в рамках этого область. Для обращения ко вложенному классу из области, отличной от непосредственно включающей его области, следует использовать полное имя.

В следующем примере показано, как объявить вложенные классы.

// nested_class_declarations.cpp class BufferedIO < public: enum IOError < None, Access, General >; // Declare nested class BufferedInput. class BufferedInput < public: int read(); int good() < return _inputerror == None; >private: IOError _inputerror; >; // Declare nested class BufferedOutput. class BufferedOutput < // Member list >; >; int main()

BufferedIO::BufferedInput и BufferedIO::BufferedOutput объявляются в BufferedIO пределах . Эти имена классов не видимы за пределами области класса BufferedIO . Однако объект типа BufferedIO не содержит объекты типа BufferedInput или BufferedOutput .

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

В предыдущем примере BufferedIO к перечислению IOError можно получить доступ непосредственно с помощью функций-членов во вложенных классах BufferedIO::BufferedInput или BufferedIO::BufferedOutput , как показано в функции good .

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

Исключением из видимости области объявления вложенного класса является объявление имени типа вместе с опережающим объявлением. В этом случае имя класса, объявленное с помощью опережающего объявления, видимо за пределами включающего класса, при этом область определена как наименьшая включающая область вне класса. Например:

// nested_class_declarations_2.cpp class C < public: typedef class U u_t; // class U visible outside class C scope typedef class V <>v_t; // class V not visible outside class C >; int main() < // okay, forward declaration used above so file scope is used U* pu; // error, type name only exists in class C scope u_t* pu2; // C2065 // error, class defined above so class C scope V* pv; // C2065 // okay, fully qualified name C::V* pv2; >

Права доступа во вложенных классах

Вложение класса в другой класс не предоставляет особые права доступа к функциям-членам вложенного класса. Аналогичным образом, функции-члены включающего класса не имеют особых прав доступа к членам вложенного класса.

Функции-члены во вложенных классах

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

// member_functions_in_nested_classes.cpp class BufferedIO < public: enum IOError < None, Access, General >; class BufferedInput < public: int read(); // Declare but do not define member int good(); // functions read and good. private: IOError _inputerror; >; class BufferedOutput < // Member list. >; >; // Define member functions read and good in // file scope. int BufferedIO::BufferedInput::read() < return(1); >int BufferedIO::BufferedInput::good() < return _inputerror == None; >int main()

В предыдущем примере синтаксис с полным именем типа используется для объявления имени функции. Объявление:

BufferedIO::BufferedInput::read() 

означает » read функция, являющаяся членом BufferedInput класса, который находится в область BufferedIO класса». Так как в этом объявлении используется синтаксис имени квалифицированного типа, возможны конструкции следующей формы:

typedef BufferedIO::BufferedInput BIO_INPUT; int BIO_INPUT::read() 

Предыдущее объявление эквивалентно предыдущему, но вместо имен классов используется typedef имя.

Дружественные функции во вложенных классах

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

// friend_functions_and_nested_classes.cpp #include enum < sizeOfMessage = 255 >; char *rgszMessage[sizeOfMessage]; class BufferedIO < public: class BufferedInput < public: friend int GetExtendedErrorStatus(); static char *message; static int messageSize; int iMsgNo; >; >; char *BufferedIO::BufferedInput::message; int BufferedIO::BufferedInput::messageSize; int GetExtendedErrorStatus() < int iMsgNo = 1; // assign arbitrary value as message number strcpy_s( BufferedIO::BufferedInput::message, BufferedIO::BufferedInput::messageSize, rgszMessage[iMsgNo] ); return iMsgNo; >int main()

В следующем коде показана функция GetExtendedErrorStatus , объявленная в качестве дружественной функции. В функции, определенной в области видимости файла, сообщение копируется из статического массива в член класса. Обратите внимание, что для оптимальной реализации функции GetExtendedErrorStatus рекомендуется объявить ее следующим образом.

int GetExtendedErrorStatus( char *message ) 

В предыдущем интерфейсе несколько классов могут использовать службы этой функции, передав адрес памяти, в которую требуется скопировать сообщение об ошибке.

Классы, структуры и пространства имен

C# является полноценным объектно-ориентированным языком. Это значит, что программу на C# можно представить в виде взаимосвязанных взаимодействующих между собой объектов.

Описанием объекта является класс , а объект представляет экземпляр этого класса. Можно еще провести следующую аналогию. У нас у всех есть некоторое представление о человеке, у которого есть имя, возраст, какие-то другие характеристики. То есть некоторый шаблон — этот шаблон можно назвать классом. Конкретное воплощение этого шаблона может отличаться, например, одни люди имеют одно имя, другие — другое имя. И реально существующий человек (фактически экземпляр данного класса) будет представлять объект этого класса.

В принципе ранее уже использовались классы. Например, тип string , который представляет строку, фактически является классом. Или, например, класс Console , у которого метод WriteLine() выводит на консоль некоторую информацию. Теперь же посмотрим, как мы можем определять свои собственные классы.

По сути класс представляет новый тип, который определяется пользователем. Класс определяется с помощью ключевого слова сlass :

class название_класса < // содержимое класса >

После слова class идет имя класса и далее в фигурных скобках идет собственно содержимое класса. Например, определим в файле Program.cs класс Person, который будет представлять человека:

class Person

Классы и объекты в языке программирования C# и .NET

Начиная с версии C# 12, если класс имеет пустое определение, то фигурные скобки после названия типа можно не использовать:

class Person;

Однако такой класс не особо показателен, поэтому добавим в него некоторую функциональность.

Поля и методы класса

Класс может хранить некоторые данные. Для хранения данных в классе применяются поля . По сути поля класса — это переменные, определенные на уровне класса.

Кроме того, класс может определять некоторое поведение или выполняемые действия. Для определения поведения в классе применяются методы.

Итак, добавим в класс Person поля и методы:

class Person < public string name = "Undefined"; // имя public int age; // возраст public void Print() < Console.WriteLine($"Имя: Возраст: "); > >

В данном случае в классе Person определено поле name , которое хранит имя, и поле age , которое хранит возраст человека. В отличие от переменных, определенных в методах, поля класса могут иметь модификаторы, которые указываются перед полем. Так, в данном случае, чтобы все поля были доступны вне класса Person поля определены с модификатором public .

При определении полей мы можем присвоить им некоторые значения, как в примере выше в случае переменной name . Если поля класса не инициализированы, то они получают значения по умолчанию. Для переменных числовых типов это число 0.

Также в классе Person определен метод Print() . Методы класса имеют доступ к его поля, и в данном случае обращаемся к полям класса name и age для вывода их значения на консоль. И чтобы этот метод был виден вне класса, он также определен с модификатором public .

Создание объекта класса

После определения класса мы можем создавать его объекты. Для создания объекта применяются конструкторы . По сути конструкторы представляют специальные методы, которые называются так же как и класс, и которые вызываются при создании нового объекта класса и выполняют инициализацию объекта. Общий синтаксис вызова конструктора:

new конструктор_класса(параметры_конструктора);

Сначала идет оператор new , который выделяет память для объекта, а после него идет вызов конструктора .

Конструктор по умолчанию

Если в классе не определено ни одного конструктора (как в случае с нашим классом Person), то для этого класса автоматически создается пустой конструктор по умолчанию, который не принимает никаких параметров.

Теперь создадим объект класса Person:

Person tom = new Person(); // создание объекта класса Person // определение класса Person class Person < public string name = "Undefined"; public int age; public void Print() < Console.WriteLine($"Имя: Возраст: "); > >

создание классов в языке программирования C# и .NET

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

Обращение к функциональности класса

Для обращения к функциональности класса — полям, методам (а также другим элементам класса) применяется точечная нотация точки — после объекта класса ставится точка, а затем элемент класса:

объект.поле_класса объект.метод_класса(параметры_метода)

Например, обратимся к полям и методам объекта Person:

Person tom = new Person(); // создание объекта класса Person // Получаем значение полей в переменные string personName = tom.name; int personAge = tom.age; Console.WriteLine($"Имя: Возраст "); // Имя: Undefined Возраст: 0 // устанавливаем новые значения полей tom.name = "Tom"; tom.age = 37; // обращаемся к методу Print tom.Print(); // Имя: Tom Возраст: 37 class Person < public string name = "Undefined"; public int age; public void Print() < Console.WriteLine($"Имя: Возраст: "); > >

Консольный вывод данной программы:

Имя: Undefined Возраст: 0 Имя: Tom Возраст: 37

Добавление класса

Обычно классы помещаются в отдельные файлы. Нередко для одного класса предназначен один файл. Если мы работаем над проектом вне среды Visual Studio, используя .NET CLI, то нам достаточно добавить новый файл класса в папку проекта. Например, добавим новый файл, который назовем Person.cs и в котором определим следующий код:

class Person < public string name = "Undefined"; public void Print() < Console.WriteLine($"Person "); > >

Здесь определен класс Person с одним полем name и методом Print.

В файле Program.cs , который представляет основной файл программы используем класс Person:

Person tom = new Person(); tom.name = "Tom"; tom.Print(); // Person Tom

Использование классов в проекте в Visual Studio в языке программирования C#

Visual Studio предоставляет по умолчанию встроенные шаблоны для добвления класса. Для добавления класса нажмем в Visual Studio правой кнопкой мыши на название проекта:

Добавление класса в Visual Studio в C#

В появившемся контекстном меню выберем пункт Add -> New Item. (или Add -> Class. )

В открывшемся окне добавления нового элемента убедимся, что в центральной части с шаблонами элементов у нас выбран пункт Class . А внизу окна в поле Name введем название добавляемого класса — пусть он будет назваться Person :

Добавление нового класса в Visual Studio в C#

В качестве названия класса можно вводить как Person, так и Person.cs. И после нажатия на кнопку добавления в проект будет добавлен новый класс, в котором можно определить тот же код и также использовать в файле Program.cs.

Таким образом, мы можем определять классы в отдельных файлах и использовать их в программе.

Использование классов внутри других классов

Бывает такое, что мы хотели бы использовать методы одного класса внутри другого, но не хотели бы наследовать от этого класса.

Почему мы не хотим наследовать?

Во-первых, используемый класс может являться вспомогательным и по логике нашего кода может не подходить на роль родителя.

Во-вторых, мы можем захотеть использовать несколько классов внутри другого класса, а с наследованием это не получится, ведь в PHP у класса может быть только один родитель.

Давайте посмотрим на практическом примере. Пусть у нас дан следующий класс Arr , в объект которого мы можем добавлять числа с помощью метода add :

Давайте теперь добавим в наш класс метод, который будет находить сумму квадратов элементов и прибавлять к ней сумму кубов элементов.

Пусть у нас уже существует класс SumHelper , имеющий методы для нахождения сумм элементов массивов:

Логично будет не реализовывать нужные нам методы еще раз в классе Arr , а воспользоваться методами класса SumHelper внутри класса Arr .

Для этого в классе Arr внутри конструктора создадим объект класса SumHelper и запишем его в свойство sumHelper :

Теперь внутри Arr доступно свойство $this->sumHelper , в котором хранится объект класса SumHelper с его публичными методами и свойствами (если бы публичные свойства были, сейчас их там нет, только публичные методы).

Создадим теперь в классе Arr метод getSum23 , который будет находить сумму квадратов элементов и прибавлять к ней сумму кубов элементов, используя методы класса SumHelper :

sumHelper = new SumHelper; > // Находим сумму квадратов и кубов элементов массива: public function getSum23() < // Для краткости запишем $this->nums в переменную: $nums = $this->nums; // Найдем описанную сумму: return $this->sumHelper->getSum2($nums) + $this->sumHelper->getSum3($nums); > public function add($number) < $this->nums[] = $number; > > ?>

Давайте воспользуемся созданным классом Arr :

add(1); // добавляем в массив число 1 $arr->add(2); // добавляем в массив число 2 $arr->add(3); // добавляем в массив число 3 // Находим сумму квадратов и кубов: echo $arr->getSum23(); ?>

Самостоятельно повторите описанные мною классы Arr и SumHelper .

Создайте класс AvgHelper с методом getAvg , который параметром будет принимать массив и возвращать среднее арифметическое этого массива (сумма элементов делить на количество).

Добавьте в класс AvgHelper еще и метод getMeanSquare , который параметром будет принимать массив и возвращать среднее квадратичное этого массива (квадратный корень, извлеченный из суммы квадратов элементов, деленной на количество).

Добавьте в класс Arr метод getAvgMeanSum , который будет находить сумму среднего арифметического и среднего квадратичного из массива $this->nums .

Как правильно использовать существующий объект одного класса в описании другого класса?

Author24 — интернет-сервис помощи студентам

Расскажу на конкретном примере.
Допустим, я создал класс для обработки данных поступающих с UART (последовательный порт)
Класс представляет собой кольцевой буфер и несколько методов для работы с ним.
Методы самые простые: сохранить байт в буфер, вытащить байт из буфера, проверить буфер на пустоту, очистить буфер и т.д.

На основе класса я создал объект.
И проблема в том что этот объект должен быть только один, а использоваться он должен во всей программе в том числе и в других классах.

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

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

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

94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:

Объявление объекта одного класса в описании другого класса
Здравствуйте. Почему при объявлении Student s в классе Teacher не возникает ошибки? Ведь такой.

Как отправить объект одного класса в метод другого класса
Начал изучать классы в c++ и в качестве практики решил написать программу которая упрощено.

Как связать сигнал одного класса со слотом другого класса, содержащего указатель на объект этого класса?
Подскажите, пожалуйста, как связать сигнал одного класса со слотом другого класса, содержащего.

Можно ли объявлять в описании одного класса объекты другого класса
Здравствуйте! Помогите, пожалуйста, разобраться: я описал класс SignalZakon, а теперь хочу создать.

Ошибка при попытке использовать объект класса в определении другого класса
Муторное название получилось :scratch: Прошу помощи. есть созданный класс работы со строкой.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *