Свойства объектов в языках С++, Java, C#. Часть 2
Выбери формат для чтения
Загружаем конспект в формате doc
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
Свойства объектов в языках С++, Java, C# ч. 2
1) Статические поля и методы на C++, Java и C#
Пример на C#
y=Math.Sin(x); // Класс Math вызывает статический метод Sin(x).
В C++ есть свободные функции, не принадлежащие классу. Можно записать:
#include
.........
y=sin(x);
Статические (static) поля и методы вызываются не объектами, а классами, они принадлежат классу целиком.
Статическое поле имеет одно и тоже значение для всех объектов C++, инициализируется один раз вне функции и если объект изменит его значение, оно изменится для всех объектов.
Статические методы могут обращаться только к статическим полям и методам.
Пример статического поля и метода в C++, Java и C#
Марафонский бег - к min, sec в Record добавлено статическое поле hour (час). Кроме этого добавлен статический метод Roundmin – округление до минут.
C++
Record.h
#pragma once
class Record
{
private:
int min,sec;
public:
void Init(int m,int s);
static int Roundmin(Record x); // статический метод
static int hour; // статическое поле
};
Record.cpp
#include "StdAfx.h"
#include "Record.h"
void Record::Init(int m,int s)
{
min=m;
sec=s;
}
int Record::Roundmin(Record x)
{
if(x.sec>=30) // if(this->sec>=30) - ошибка, обращение к не статическому полю
return x.min+1;
else
return x.min;
}
int Record::hour=1; // инициализация статического поля вне класса
Lab5.cpp
#include "stdafx.h"
#include "Record.h"
int _tmain(int argc, _TCHAR* argv[])
{
int k;
Record a,b;
a.hour=3; // у b : hour=3 !
a.Init(4,55);
k=Record::Roundmin(a); // вызов статического метода k=5
return 0;
}
Java:
class Record
{
private int min,sec;
static int hour; // статическое поле
public void Init(int m,int s)
{
min=m;
sec=s;
}
static int Roundmin(Record x) // статический метод
{
int z;
if(x.sec>=30)
{
return x.min+1;
}
else
{
return x.min;
}
}
}
public class lab5
{
public static void main(String[] args)
{
Record a= new Record();
Record b=new Record();
a.Init(3, 5);
b.Init(2, 45);
a.hour=2; // присваивание статическому полю b.hour =2 всем объектам !
int z;
z=Record.Roundmin(b); // вызов статического метода
}
}
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Record
{
private int min, sec;
public static int hour; // статическое поле
public void Init(int m, int s)
{
min = m;
sec = s;
}
static public int Roundmin(Record x) // статический метод
{
if (x.sec >= 30)
{
return x.min + 1;
}
else
{
return x.min;
}
}
}
class Program
{
static void Main(string[] args)
{
Record a = new Record();
Record b = new Record();
a.Init(3, 5);
b.Init(2, 45);
Record.hour = 2; // вызов статического поля через класс!
int z;
z = Record.Roundmin(b); // вызов статического метода z=3
}
}
}
Практический пример класса (Java) со статическими методами
Небольшая математическая библиотека с функциями, отсутствующими в Math.
import java.lang.Math.*;
class MyMath // класс расширение мат. методов
{
static public double drob(double x) // Дробная часть числа
{
return x - (int)x;
}
static public double ctg(double x) // котангенс
{
return Math.cos(x)/Math.sin(x);
}
}
public class lab5
{
public static void main(String[] args)
{
// TODO code application logic here
double y,z;
double u,v;
u=48.12;
v=1.5;
z= MyMath.ctg(v);
y=MyMath.drob(u); // y=0.12
}
}
2) Конструкторы инициализации и деструктор на C++, Java и C#
Конструкторы – специальные методы класса, имя конструктора совпадает с именем
класса и отсутствует тип, в том числе void, вызываются при инициализации объектов.
Конструкторы могут быть с числом параметров, равным числу полей, меньшим числом параметров или без параметров. Конструкторов может быть несколько (перегрузка!)
C++
Конструктор с 2 параметрами
В классе Record заменим Init конструктом с двумя параметрами.
class Record
{
private:
int min,sec;
public:
void Display();
/* вместо void Init(int m,int s); */
Record(int m,int s); // конструктор
};
void Record::Display()
{
printf(“%d %d “,min,sec);
}
Record::Record(int m,int s) // конструктор
{
min=m;
sec=s;
}
int main(int argc, char* argv[])
{
Record z(2,5); // вызов конструктора в момент объявления вместо z.Init(2,5)
z.Display();
Record *x;
x=new Record(1,4); // вызов конструктора динамического объекта оператор new
x->Display();
delete x;
}
Добавим конструктор с одним параметром и без параметров.
class Record
{
public:
int min,sec;
void Display();
Record(int m,int s); // конструктор с 2 параметрами
Record(int m); // конструктор с 1 параметром
Record(); // конструктор без параметров
};
void Record::Display()
{
printf(“%d %d “,min,sec);
}
Record::Record(int m,int s) // с двумя параметрами
{
min=m;
sec=s;
}
Record::Record(int m) // с одним параметром
{
min=m;
sec=0;
}
Record::Record() // без параметров
{
min=0;
sec=1;
}
int main(int argc, char* argv[])
{
Record z(2,5); // вызов конструктора 1
z.Display();
Record a(6); // 2 конструктор a.min=6 sec=0
a.Display();
Record c; // 3 конструктор c.min=0 c.sec=1
c.Display();
Record *d;
d=new Record(5); // 3 конструктор динамический объект min=5 sec=0
d->Display();
delete d;
}
Конструктором с одним параметром можно инициализировать массив объектов
class Record
{
public:
void Display();
Record(int m); // конструктор с одним параметром
private:
int min;
int sec;
};
void Record::Display()
{
printf("%d %d ",min,sec);
}
Record::Record(int m) // конструктор с одним параметром
{
min=m;
sec=0;
}
int main(int argc, char* argv[])
{
Record z[5]={1,2,3,4,5}; // z[0].min=1 z[1].min=2... z[4].min=5 sec=0 у всех элементов
...
}
Если в классе нет конструкторов, создается пустой конструктор без параметров, при создании объектов вызывается этот конструктор.
int main(int argc, char* argv[])
{
Record z; // вызов пустого конструктора по умолчанию значения min sec не определены
...........
Если есть хоть один конструктор, конструктор по умолчанию не создается
class Record
{
public:
void Display();
Record(int m,int s); // конструктор с 2 параметрами
private:
int min;
int sec;
};
void Record::Display()
{
printf("%d %d ",min,sec);
}
Record::Record(int m,int s) // конструктор с 2 параметрами
{
min=m;
sec=s;
}
int main(int argc, char* argv[])
{
Record z(1,4); // min=1 sec=4
Record y; // ошибка, нет конструктора без параметров!
}
Деструктор.
Деструктор в программе один, не имеет типа, как конструктор и не имеет аргументов, вызывается при завершении модуля, где определен статический объект или оператором delete для динамического объекта
class Student
{
public:
void Display();
Student(char *s,int k); // конструктор фамилия, курс
~Student(); // деструктор
private:
char Fam[30];
int Kurs;
};
void Student::Display()
{
printf("%s %d \n",Fam,Kurs);
}
Student::Student(char *s,int k)
{
strcpy(Fam,s);
Kurs=k;
}
Student::~Student() // деструктор
{
printf("%s %s\n",Fam,"удален");
}
int main(int argc, char* argv[])
{
Student x("Иванов",3);
x.Display();
Student *y;
y=new Student;
y->Init("Петров",2);
y->Display();
delete y; // вызов деструктора
} // вызов деструктора
Вывод на консоль:
Иванов 3
Петров 2
Петров удален
Иванов удален
Мнемоническое правило:
Конструктор для статического объекта вызывается всегда в момент его объявления
(Record c;) . Для динамического объекта через new (Record x; x=new Record(); ) . Если нет конструкторов, то создается пустой. Деструктор вызывается для статического объекта в момент выхода из функции, где он объявлен, для динамического вызывается delete. Если нет деструктора, создается пустой.
Java
package javaapplication10;
class Record
{
private int min,sec;
public Record(int m,int s)
{
min=m;
sec=s;
}
public Record(int m)
{
min=m;
sec=0;
}
public Record()
{
min=0;
sec=1;
}
public class lab5
{
public static void main(String[] args)
{
// TODO code application logic here
Record a= new Record(3,5); // с 2 параметрами
Record b=new Record(2); // 1 параметр min=2 sec=0
Record c=new Record(); // без параметров min=0 sec=1
Record d[]=new Record[5];
int i;
for(i=0;i<5;i++)
{
d[i]=new Record(i); // у всех элементов sec=0; d[0].min=0; d[1].min=1 ...
}
}
}
Замечание по деструктору. Деструктор отсутствует, есть метод finalize();
class Record
{
........
protected void finalize() // вызов при сборке мусора
{
System.out.printf("объект %d %d уничтожен", min,sec);
}
.....
}
вызывается, когда происходит сборка мусора (неизвестно, когда).
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Record
{
private int min, sec;
public Record(int m, int s) // с двумя параметрами
{
min = m;
sec = s;
}
public Record(int m) // с одним параметром
{
min = m;
sec = 0;
}
public Record() // без параметров
{
min = 0;
sec = 1;
}
~Record() // деструктор, вызывается перед сборкой мусора, т.е. неизвестно когда
{
Console.WriteLine("Объект {0} {1} уничтожен", min,sec);
}
class Program
{
static void Main(string[] args)
{
Record a = new Record(3,5);
Record b = new Record(2);
Record c = new Record();
Record []d =new Record[5];
int i;
for (i = 0; i < 5; i++)
{
d[i] = new Record(i); // конструктор с одним параметром
}
}
}
}
3) Конструктор копирования на C++
Конструктор копирования без параметров по умолчанию создается всегда, даже если есть конструкторы инициализации и копирования с параметрами, если он не перегружен явно без параметров.
class Record
{
private:
int min,sec;
public:
Record(); // конструктор инициализации без параметров
};
Record::Record()
{
min=1;
sec=2;
}
int _tmain(int argc, _TCHAR* argv[])
{
Record a; // min=1 sec=2 конструктор инициализации без параметров
Record b=a; // вызов конструктора копирования по умолчанию b: min=1 sec=2
// копируются поля a в b
Record c(a); // вызов конструктора копирования по умолчанию с: min=1 sec=2
Record d=Record(b); // вызов конструктора копирования по умолчанию d: min=1 sec=2
return 0;
}
Перегрузка конструктора копирования.
#include "stdafx.h"
class Record
{
private:
int min,sec;
public:
Record(); // конструктор без параметров
Record(int m,int s); // конструктор с параметрами
Record (Record & r); // конструктор копирования
};
Record::Record()
{
min=1;
sec=2;
}
Record::Record(int m,int s)
{
min=m;
sec=s;
}
Record::Record(Record &r) // r - возвращаемый параметр аргумента - ссылка
{
this->min=r.min*2; // минуты удваиваются при копировании
this->sec=r.sec+3; // к секундам прибавляется 3
}
int _tmain(int argc, _TCHAR* argv[])
{
Record a(3,4); // min=3 sec=4
Record b=a; // конструктор копирования, т.к. b создается : min=6 sec=7
Record c; // конструктор без параметров min=1 sec=2
Record d(c); // конструктор копирования min=2 sec=5
Record e; // конструктор без параметров min=1 sec=2
b=e; // присваивание, b был создан ранее; b: min=1 sec2
return 0;
}
Обычно параметр в конструкторе копирования объявляется const (не изменяемым)
...................
Record (const Record & r); // конструктор копирования с const
..........................
Record::Record(const Record &r)
{
this->min=r.min*2;
this->sec=r.sec+3;
}
Без const возможен конструктор, меняющий поля копируемого объекта.
Record::Record( Record &r)
{
this->min=r.min*2;
this->sec=r.sec+3;
r.min=0; // изменение поля копируемого
}
......
Record a; // min=1 sec=2
Record b=a; // b: min=2 sec=5 a: min=0 !
Перегрузка конструктора с дополнительным параметром, при этом конструктор копии по умолчанию создается!!
class Record
{
private:
int min,sec;
public:
Record();
Record (const Record & r,int m); // конструктор копирования
// с дополнительным параметром
};
Record::Record()
{
min=1;
sec=2;
}
Record::Record( const Record &r,int m)
{
this->min=m;
this->sec=r.sec+3;
`}
int _tmain(int argc, _TCHAR* argv[])
{
Record a; // a: min=1 sec=2
Record c=Record(a,7); // вызов конструктора копирования
// с дополнительным параметром c: min=7 sec=5
Record b=a; // вызов конструктора копирования по умолчанию
// конструктор создается, т.к. нет перегрузки
// Record (const Record & r);
// b: min=1 sec=2 поля копируются
return 0;
}
4) "Мелкое"(shallow) и "глубокое"(deep)копирование на C++
В классе Person есть год рождения и фамилия в виде массива char.
#include
class Person
{
private:
char Fam[20];
int Year;
public:
Person(char *f,int y); // конструктор с параметрами
Person(const Person &p); // копирующий конструктор
void Putfam(char *f); // задание новой фамилии
void Putyear(int y); // задание года рождения
};
Person::Person(char *f,int y)
{
strcpy(Fam,f);
Year=y;
}
Person::Person(const Person &p)
{
strcpy(this->Fam,p.Fam);
this->Year=p.Year;
}
void Person::Putfam(char *f)
{
strcpy(Fam,f);
}
void Person::Putyear(int y)
{
Year=y;
}
int _tmain(int argc, _TCHAR* argv[])
{
Person a("Иванова",1990);
Person b=a; // конструктор копирования b: Иванова 1990
a.Putyear(1992);
a.Putfam("Петрова"); // a:Петрова 1992, b: Fam осталась Иванова 1990
return 0;
}
Заменим массив char на указатель:
#include "stdafx.h"
#include
class Person
{
private:
char *Fam; // указатель фамилии
int Year;
public:
Person(char *f,int y); // конструктор с параметрами
Person(const Person &p); // копирующий конструктор
void Putfam(char *f); // задание новой фамилии
void Putyear(int y);
};
Person::Person(char *f,int y)
{
Fam=new char[20]; // выделение памяти для фамилии
strcpy(Fam,f);
Year=y;
}
Person::Person(const Person &p)
{
this->Fam=p.Fam; // присваивание указателя! это мелкое копирование
this->Year=p.Year;
}
void Person::Putfam(char *f)
{
strcpy(Fam,f);
}
void Person::Putyear(int y)
{
Year=y;
}
int _tmain(int argc, _TCHAR* argv[])
{
Person a("Иванова",1990);
Person b=a; // конструктор копирования b: Иванова 1990
a.Putyear(1992);
a.Putfam("Петрова"); // b: Петрова 1990 !! фамилия меняется синхронно (указывают на одну область памяти), а год рождения остался прежним.
return 0;
}
Исправление. Глубокое копирование.
...................
Person::Person(const Person &p)
{
Fam=new char(strlen(p.Fam)+1); // выделение памяти из кучи для нового объекта
strcpy(this->Fam,p.Fam); // копирование в выделенную память
this->Year=p.Year;
}
.......
int _tmain(int argc, _TCHAR* argv[])
{
Person a("Иванов",1980);
Person b=a;
a.Putfam("Петров"); // b: осталась Иванова 1990
return 0;
}
5) Перегрузка оператора присваивания на C++
В C++ возможна перегрузка большинства операторов, в том числе оператора присваивания, в Java перегрузка операторов отсутствует, в C# имеется перегрузка операторов, но нет перегрузки оператора присваивания.
При присваивании динамических объектов они указывают на ту же область памяти и при изменении полей одного объекта автоматически меняются поля другого.
class Record
{
private:
int min,sec;
public:
Record(int m,int s); // конструктор с параметрами
void Putmin(int m); // задание значению поля
};
Record::Record(int m,int s)
{
min=m;
sec=s;
}
void Record::Putmin(int m)
{
min=m;
}
int _tmain(int argc, _TCHAR* argv[])
{
Record a (2,4);
Record b(3,5);
a=b;
b.Putmin(5); // b: min=5 sec=5 a: min=3 sec=5 – у a прежние значения полей после присваивания
Record *c = new Record(2,4);
Record *d=new Record(3,5);
c=d; // c и d указывают на одну и ту же область памяти
d->Putmin(5); // d: min=5 sec=5 c: min=5 sec=5 ! изменение в одной области памяти
return 0;
}
Можно выполнить присваивание содержимого объектов (копирование полей):
*c=*d; // вместо c=d; - объекты указывают на разные области
d->Putmin(5); // d: min=5 sec=5 c: min=3 sec=5 остались прежними
В случае наличия указателей при присваивании содержимого объектов происходит мелкое копирование. Пусть в классе Person имеются поля Year – год рождения и указатель Fam.
#include "stdafx.h"
#include
class Person
{
private:
char *Fam;
int Year;
public:
Person(char *f,int y); // конструктор с параметрами
void Putfam(char *f); // задание новой фамилии
void Putyear(int y); // задание нового года рождения
};
Person::Person(char *f,int y)
{
Fam=new char[20]; // выделение памяти для фамилии
strcpy(Fam,f);
Year=y;
}
void Person::Putfam(char *f)
{
strcpy(Fam,f);
}
void Person::Putyear(int y)
{
Year=y;
}
int _tmain(int argc, _TCHAR* argv[])
{
Person *a;
a=new Person("Иванова",1990);
Person *b;
b=new Person("Петрова",1992);
*b=*a; // копирование содержимого - год рождения и указатель (!) на область с фамилией ; b: Иванова 1990
a->Putyear(1992);
a->Putfam("Петрова"); // занесение по указателю Fam
// b: Year =1992 год остался Fam="Петрова" !! Fam в той же области
return 0;
}
Если у класса имеются указатели, стандартный метод перегрузки оператора присваивания с глубоким копированием имеет вид.
#include "stdafx.h"
#include
class Person
{
private:
int Year;
char *Fam;
public:
Person(char *f,int y);
void Putfam(char *f);
void Putyear(int y);
Person & operator = (Person &p); // перегрузка оператра присваивания
};
Person::Person(char *f,int y) // конструктор с параметрами
{
int k;
Year=y;
k=strlen(f)+1;
Fam=new char[k]; // выделение памяти столько, сколько у аргумента
strcpy(Fam,f);
}
void Person::Putfam(char *f) // задание фамилии объекту
{
strcpy(Fam,f);
}
void Person::Putyear(int y)
{
Year=y;
}
Person & Person::operator = (Person &p) // перегрузка присваивания (глубокое)
{
int k;
if(Fam)
{
delete Fam; // очистка паяти Fam
}
Fam=NULL;
this->Year=p.Year; // копирование обычного поля
k=strlen(p.Fam)+1;
Fam=new char[k]; // выделение памяти для новой копии памяти для Fam
strcpy(this->Fam,p.Fam); // копирование в новую выделенную область
return *this;
}
int _tmain(int argc, _TCHAR* argv[])
{
Person *a;
a=new Person("Иванова",1990);
Person *b;
b=new Person("Петрова",1992);
*b=*a; // перегруженный оператор присваивания b: Иванова 1990, но Fam в новой области отдельно от a !
a->Putyear(1992);
a->Putfam("Петрова"); // b – остались Иванова 1990 !
return 0;
}
6) Исключения на C++, Java и C#
C++
Ошибки времени выполнения.
Класс exception на C++ [catch (exception &e)] используется для встроенных ошибок. Открыть для чтения несуществующий файл, перевести в число строку (“-4.45,6”), деление на нуль.
Не работающий в Visual Studio пример.
#include
#include
#include
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
int x = 0;
try // блок в котором могут быть ошибки (исключения)
{
cout <<1/x; // Исключение. Последующие операторы в try выполняться не будут
}
catch (...) // ловить все исключения (многоточие)
{
cout << "Деление на ноль";
}
return 0;
}
Исключения, генерируемые программой.
Исключения могут совпадать с системными (выход за границы массива) или тем, что программист считает за ошибку (возраст <0 или >100).
Пример.
Вычисление числа, обратного сумме двух введенных чисел:
z=1/(x+y)
#include "stdafx.h"
#include
#include
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
float x,y,z;
cin >> x >> y;
z=1/(x+y);
cout << z;
return 0;
}
При вводе 2 -2 возникает деление на нуль. В стандартном компиляторе – сообщение "деление на нуль" и завершение программы.
1.#iINF - обработка интегрированной средой (Visual Studio) и продолжение работы программы.
Обработка деления на нуль с помощью исключения внутри программы.
try, throw, catch
catch{ } следует за try{ } и выполняет действия на оператор throw.
int _tmain(int argc, _TCHAR* argv[])
{
float x,y,z;
cin >> x >> y;
try // попытка вычисления
{
if(x==-y)
throw 0; // исключение (тип исключения - целый), при выполнении условия if
z=1/(x+y); // если вып. throw – не вычисляются операторы до закр. } от try
// иначе выполняется деление
}
catch(...) // ... многоточие - ловить все типы исключения
{
z=0;
}
return 0;
}
Ввод 2 -2 -> z=0
Возможные типы исключения – целое число, символ, строка, объект класса.
throw 0; и throw 1; - одно и то же.
Вариант программы – тип исключения - строка и блоки try{ } catch{ } находятся не в функции, где произошло исключение throw.
#include "stdafx.h"
#include
#include
using namespace std;
float f(float x,float y) // вспомогательная функция
{
if (x==-y)
{
throw "bad numbers"; // исключение типа строка
}
return 1/(x+y); // в случае исключения оператор пропускается
}
int _tmain(int argc, _TCHAR* argv[])
{
float x,y,z;
int p;
p=0;
while (p==0) // пока не введены правильные числа
{
p=1;
cin >> x >> y;
try // попытка вычислить функцию
{
z=f(x,y);
}
catch (char *s) // ловить только тип исключения - строку
{
cout << "Введите другие числа";
cout << '\n';
p=0; // снова ввод
}
if (p==1) // вычислено
{
cout << z;
}
}
return 0;
}
Вывод:
2 -2
Введите другие числа
4 2
0.166667
При срабатывании исключения throw сначала ищется try внутри функции с исключением – [в примере f(x,y)], если try отсутствует, try ищется в функции, вызвавшей f(x,y) [в примере main]. Если нет - в следующей вызвавшей функции и т.д. Движение вверх по стеку.
При обнаружении try, проверяется тип следующего за try блока
catch{ } . Если подходит для throw, исключение обрабатывается в catch.
в примере -[catch (char *s) ловит и выводит “Введите другие числа”].
Пример двух исключений в программе.
Вычисление факториала, исключениями считаются отрицательный аргумент (первое исключение) и аргумент равный нулю (второе исключение).
#include "stdafx.h"
#include
#include
using namespace std;
int fact(int n)
{
int i,p;
try
{
if(n==0)
throw '0'; // для n=0 тип исключения - символ
if(n<0)
throw 1; // для отрицательного n тип исключения – целое число
}
catch (char c) // ловится тип исключения - символ
{
printf( "Аргумент равен нулю "); // исключение символ, аргумент равен нулю
return -1;
}
// оба исключения не сработали, вычисление факториала
p=1;
for(i=1;i<=n;i++)
p=p*i;
return p;
}
int _tmain(int argc, _TCHAR* argv[])
{
int n,f;
char c;
scanf("%d",& n);
try // блок try в вызывающей программе
{
f=fact(n);
}
catch(int k) // ловится тип исключения целое, аргумент n отрицателен
{
printf( "Аргумент отрицателен");
return 0;
}
if(f>=0)
printf( "%d \n",f);
return 0;
}
Примеры:
Аргумент равен 0
-2
Аргумент отрицателен
4
24
Java
В java при возникновении возможности ошибки использование блоков try{ } и
catch(Exception е){} обязательно. При отсутствии – ошибка компиляции.
пример обработки системных исключений на java:
public class TestTry
{
public static void main(String args[])
{
try
{
int a ;
a=0;
int b;
b = 10 / a; // деление на нуль
int c[] = { 1 };
c[6] = 99; // выход за границу массива
}
catch (ArithmeticException e) // исключение в арифметических операциях
{
System.out.printf("деление на ноль: " + e); // e - сообщение класса exception
}
catch(ArrayIndexOutOfBoundsException e) // исключение – выход за границу массива
{
System.out.printf("неправильный индекс массива: " + e); // e - сообщение класса exception
}
}
}
Вывод – сработало первое исключение
деление на ноль: java.lang.ArithmeticException: / by zero
Если заменить на
a=1;
вывод – сработало второе исключение
неправильный индекс массива: java.lang.ArrayIndexOutOfBoundsException: 6
Пример исключения, генерируемого программой.
Вычисление факториала, исключения: первое - аргумент равен 0, второе - аргумент меньше 0
package javaapplication1;
import java.util.*;
class Ex extends Exception // подкласс от общего класса исключений
{
private int Type; // номер варианта исключения
Ex(int a) // конструктор определяемого класса
{
Type = a;
}
public String toString() // перегрузка встроенного метода Exception перевода в строку сообщения
{
if(Type==2)
return "Аргумент<0"; // Сообщение второго исключения
else
return "Аргумент=0"; // Сообщение первого исключения
}
}
public class calculate
{
static int fact(int n) throws Ex // факториал с исключениями
{
int i,p;
if(n<0)
throw new Ex(1); // 1 вариант исключения =0
if(n==0)
throw new Ex(2); // 2 вариант исключения <0
p=1; // вычисления, аргумент положителен
for(i=1;i<=n;i++)
p=p*i;
return p;
}
public static void main(String[] args)
{
int n,f;
Scanner inp= new Scanner(System.in);
n = inp.nextInt();
inp.close();
f=1;
try
{
f=fact(n);
}
catch ( Ex e) // блок catch оба исключения в блоке
{
System.out.printf("исключение: " + e);
return;
}
System.out.printf("f= %d",f);
}
}
Вывод:
Аргумент=0
-2
Аргумент<0
4
24
C#
Исключения системные и пользовательские (генерируемые программой).
Пример системных исключений.
Вычислить z=1/(x+y)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
double x, y, z;
string s;
s = Console.ReadLine();
x = Convert.ToDouble(s);
s = Console.ReadLine();
y = Convert.ToDouble(s);
z = 1/(x+ y);
Console.WriteLine(z);
Console.ReadKey();
}
}
}
Ввод и вывод:
3
1
0,25
3
qw
FormatException не обработано
Входная строка имела неверный формат.
2
-2
// z=Infinity
Visual Studio обрабатывает деление на нуль вещественного числа.
Обработка неправильного формата числа (строка не переводится в число) и деления на нуль программой.
static void Main(string[] args)
{
int x, y, z;
string s;
x = 1; // иначе ошибка компиляции x должен быть инициализирован
s = Console.ReadLine();
try // перевод введенной строки в целое
{
x = Convert.ToInt32(s);
}
catch(FormatException) // исключение неправильный формат
{
Console.WriteLine("введенная строка - не число. Нажмите любую клавишу");
Console.ReadKey();
return;
}
s = Console.ReadLine();
y = Convert.ToInt32(s);
z = 0;
try
{
z = 10/(x+y); // вычисление
}
catch (DivideByZeroException) // исключение деление на нуль
{
Console.WriteLine("деление на нуль. Нажмите любую клавишу");
Console.ReadKey();
return;
}
Console.WriteLine(z); // Вычислить возможно
Console.ReadKey();
}
Вывод
5
2
1
5
qw
x-не число. Нажмите любую клавишу
2
-2
деление на нуль. Нажмите любую клавишу
Пользовательские исключения выбрасываются через throw, перехватываются в catch, который следует за блоком try. Если данное исключение не перехватывается catch в методе, выполняется поиск по вызывающим методам (поиск по стеку), если не найдено, сообщение необработанное исключение. Аналогично C++
Вычисление факториала, исключения - аргумент равен нулю и аргумент меньше нуля. Первое исключение перехватывается в функции fact, второе в main.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static Exception e1; // = new Exception(""); // первое исключение объект класса Exception
static Exception e2; // = new Exception(""); // второе исключение
static int fact(int n)
{
int i, p;
p = 1;
try
{
if (n == 0)
{
throw e1 = new Exception("Аргумент=0"); // 1 исключение
}
if (n < 0)
{
throw e2 = new Exception("Аргумент<0"); // 2 исключение
}
for (i = 1; i <= n; i++)
p = p * i;
}
catch (Exception e1) // перехват первого исключения в функции
{
string s;
s = e1.Message; // s="Аргумент=0"
Console.WriteLine(s);
Console.ReadKey();
System.Environment.Exit(0); // завершение программы
}
return p;
}
static void Main(string[] args)
{
int n, f;
string s;
f = 1;
s=Console.ReadLine();
n = Convert.ToInt32(s);
try
{
f = fact(n);
}
catch (Exception e2) // перехват второго исключения
{
s = e2.Message; // s="Аргумент<0"
Console.WriteLine(s);
Console.ReadKey();
System.Environment.Exit(0);
}
s = Convert.ToString(f); // вывод значения факториала
Console.WriteLine(s);
Console.ReadKey();
}
}
}
Аргумент=0
-2
Аргумент<0
4
24
7)Массивы в качестве аргументов методов на C++, Java и C#
В языке Си и С++ одномерные массивы передаются через указатель (вариант метода класса статический):
#include "stdafx.h"
class Record
{
public:
Record(int m,int s);
static void Arr(double *a,int n);
private:
int min;
int sec;
};
void Record::Arr(double *a,int n)
{
int i;
for(i=0;i
Тебе могут подойти лекции
А давай сэкономим
твое время?
твое время?
Дарим 500 рублей на первый заказ,
а ты выбери эксперта и расслабься
Включи камеру на своем телефоне и наведи на Qr-код.
Кампус Хаб бот откроется на устройстве
Не ищи – спроси
у ChatGPT!
у ChatGPT!
Боты в Telegram ответят на учебные вопросы, решат задачу или найдут литературу
Попробовать в Telegram
Оставляя свои контактные данные и нажимая «Попробовать в Telegram», я соглашаюсь пройти процедуру
регистрации на Платформе, принимаю условия
Пользовательского соглашения
и
Политики конфиденциальности
в целях заключения соглашения.
Пишешь реферат?
Попробуй нейросеть, напиши уникальный реферат
с реальными источниками за 5 минут
с реальными источниками за 5 минут
Свойства объектов в языках С++, Java, C#. Часть 2
Хочу потратить еще 2 дня на работу и мне нужен только скопированный текст,
пришлите в ТГ