В С# производный класс создается постановкой двоеточия после имени производного класса и указанием имени базового класса:
Классы и объекты
Структуры и классы
Все типы в С# разделяются на две основные разновидности: структурные типы (value-based) и ссылочные типы (reference-based). К структурным типам относятся все числовые типы данных (int, float и пр.), а также перечисления и структуры. Память для структурных типов выделяется из стека. При присвоении одного структурного типа другому присваивается не сам тип (как область в памяти), а его побитовая копия.
Пример. Приложение ValandRef из Э.Троелсен, стр. 89.
namespace ValandRef
{
using System;
struct FOO
{
public int x, y;
}
// Структурный тип
struct PERSON
{
public string Name;
public int Age;
public override string ToString()
{
return "Name: " + Name + ", Age: " + Age;
}
public PERSON(string n, int a)
{
Name = n; Age = a;
}
};
// Ссылочный тип
class Person
{
public string Name;
public int Age;
public override string ToString()
{
return "Name: " + Name + ", Age: " + Age;
}
public Person(string n, int a)
{
Name = n; Age = a;
}
};
class ValRefClass
{
public static int Main(string[] args)
{
FOO f1 = new FOO();// Здесь new можно не использовать.
f1.x = 100;
f1.y = 100;
FOO f 2 = f 1; // Скопировали одну структуру в другую.
Console.WriteLine("F1.x = {0}", f1.x);
Console.WriteLine("F1.y = {0}", f1.y);
Console.WriteLine("F2.x = {0}", f2.x);
Console.WriteLine("F2.y = {0}", f2.y);
// Изменяем f2.x. Это не влияет на f1.x.
Console.WriteLine("Изменили f2.x");
f2.x = 900;
Console.WriteLine("F2.x = {0}", f2.x);
Console.WriteLine("F1.x = {0}", f1.x);
// Создаем объект, т.е. ссылку в управляемой куче
|
|
Person fred; = new Person("Fred", 9);
Console.WriteLine(fred);
// Создаем значение в стеке
PERSON mary = new PERSON("Mary", 18);
Console.WriteLine(mary);
//Создаем побитовую копию:
PERSON jane = mary;
jane.Age = 20;
Console.WriteLine(jane);
Console.WriteLine(mary);
// А здесь всего лишь дополнительная ссылка на тот же объект
Person fredRef = fred;
fred.Age = 20;
Console.WriteLine(fred);
Console.WriteLine(fredRef);
return 0;
}
}
}
Структуры выглядят как классы, но реализованы по-другому. Структуры обрабатываются как типы со значением и хранятся в стеке. Это означает, что если экземпляр структуры выходит из области видимости, он автоматически удаляется из памяти. Объекты хранятся в куче и удаляются из памяти при выполнении операции под названием “сборка мусора”. Это основное различие между структурами и объектами.
Также как и классы структуры могут иметь данные, методы и конструкторы.
Укажем отличия:
Структуры не поддерживают наследования.
Для структур нельзя определить конструктор по умолчанию. В C # для структур существует конструктор по умолчанию и его нельзя переопределить.
Для структур нельзя определить деструктор.
Нельзя использовать инициализаторы для установки значений полей.
|
|
Структура объявляется при помощи ключевого слова struct, класс – при помощи ключевого слова class.
Как создать новый класс
В окне Solution Explorer выберем приложение и щелкнем правой кнопкой мыши, в контекстном меню откроем пункт “Add”, а затем пункт “Add Class…”
В следующем окне зададим имя нового класса, в нашем примере, это HelloApp:
Пример. Решение квадратного уравнения.
Файл Equation.cs.
using System;
namespace MathExample1
{
/// <summary>
/// Summary description for Equation.
/// </summary>
public class Equation
{
double a,b,c; // Коэффициенты квадратного уравнения
double x1, x2; //Корни уравнения
public Equation(double a_, double b_, double c_)
{
a=a_;b=b_;c=c_;
|
|
}
|
|
public Equation()
{
a=b=c=0;x1=x2=0;
}
public double Determinant()
{
return b * b - 4 * a* c;
}
public void SolveEquation()
{
double r;
// А если a=0?
r = Determinant();
if (r<0) Console.WriteLine("Нет корней!");
else
if (r>0) {
r=Math.Sqrt(r);
x1=(-b+r)/(2*a);
x2=(-b-r)/(2*a);
}
else {x1=x2=-b/(2*a);}
}
public void DisplayRoots()
{
SolveEquation();
Console.WriteLine("x1={0} x2={1}",x1,x2);
}
}
}
Файл EquationExample.cs
using System;
namespace MathExample1
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class EquationExample
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Equation eq1 = new Equation(1,4,-5);
eq1.DisplayRoots();
}
}
}
В С# все типы данных (как структурные, так и ссылочные) производятся от единого общего предка: класса System.Object. Класс System.Object определяет общее полиморфическое поведение для всех типов данных
Подробности см. Э.Троелсен, стр. 90.
Модификаторы доступа
В С# для каждого метода существует свой уровень доступа, который определяет, откуда можно будет обратиться к данному методу. Для указания уровня доступа при объявлении метода используются специальные модификаторы.
public Модификатор общедоступности метода
private Метод будет доступен только из класса, в котором определен данный метод. Если при объявлении метода модификатор явно не указан, по умолчанию используется модификатор private
protected Метод будет доступен как из класса, в котором он определен, так и из любого производного класса. Для остальных вызовов из внешнего мира этот метод будет недоступен
internal Метод будет доступен из всех классов внутри сборки, в которой он определен. Из-за пределов этой сборки обратиться к нему будет нельзя.
Атрибуты и операции
Класс в С#, как и в других языках программирования, — это пользовательский тип данных (user defined type, UDT), который состоит из данных (часто называемых атрибутами или свойствами) и функциями для выполнения с этими данными различных действий (эти функции обычно называются методами или операциями).
Ключевое слово this используется для ссылки на текущий экземпляр объекта.
Главная причина, по которой в конструкторах используется слово this, — желание избежать конфликтов между именами принимаемых параметров и именами внутренних переменных-членов класса. Конечно же, такого конфликта можно избежать и более простым способом — определить для принимаемых переменных имена, отличные от имен переменных-членов класса.
Пример.
public class Equation
{
double a,b,c; // Коэффициенты квадратного уравнения
double x1, x2; //Корни уравнения
public Equation(double a_, double b_, double c_)
{
a=a_;
b=b_;
c=c_;
}
Или
public class Equation
{
double a,b,c; // Коэффициенты квадратного уравнения
double x1, x2; //Корни уравнения
public Equation(double a, double b, double c)
{
this.a=a;
this.b=b;
this . c = c ;
}
Зарезервированное слово this в С# можно также использовать для передачи вызова от одного конструктора к другому. Вот пример (См. Э.Троелсен, стр. 142):
class Employee
{
// Внутренние закрытые данные класса
private string fullName;
private int empID;
private float currPay;
public Emp1oyee(string fullName, int empID, float currPay)
{
this.fullName =fullname;
this.empID = empID;
this.currPay = currPay;
}
// При вызове следующего конструктора на самом деле будет вызван
// конструктор с тремя параметрами
public Employee(string fullName)
:this(fullName, 123, 0) {}
public Employee(string fullName, int empID)
:this(fullName, empID, 0) {}
}
Для каждого члена класса необходимо указать область видимости с помощью одного из следующих ключевых слов: public , private , protected и internal. Однако область видимости задается не только для членов класса, но и для самих классов . Разница между областью видимости для членов классов и областью видимости для самих классов заключается в том, что в первом случае мы определяем те члены класса, которые будут доступны через экземпляры объектов, а во втором — те области программы, из которых будет возможно обращение к данным классам.
Для класса в С# используется только два ключевых слова для определения области видимости: publiс и intern al. Объекты классов, определенных как public (открытых), могут быть созданы как из своего собственного двоичного файла, так и из других двоичных файлов С# (то есть из другой сборки).
Объекты классов определенных как internal, могут создаваться только объектами из той же сборки, в которой они были определены. Внутренние классы часто рассматриваются как вспомогательные (helper classes), поскольку они используются типами данной сборки для помощи в выполнении каких-либо действий. См. пример (Э.Троелсен, стр. 144).
Принцип инкапсуляции предполагает, что к внутренним данным объекта нельзя обратиться напрямую через экземпляр объекта.
Термин поле (field) используется для открытых данных класса (объявленных как public).
В С# инкапсуляция реализуется на уровне синтаксиса при помощи ключевых слов public, private и protected.
Для обращения к внутренним данным необходимо создать пару методов. С помощью первого метода производится получение информации (это get method или accessor). С помощью второго метода вносятся изменения (это set method или mutator).
// пример (Э.Троелсен, стр. 151).
public class Employee
{
private string fullName;
// Метод доступа
public string GetFullName() {return fullName; }
// Метод изменения
public void SetFullName (string n)
{
// Логика для удаления неположенных символов (!. @, #. $. %
// Логика для проверки максимальной длины и прочего
fullName = n;
}
}
// Применение методов доступа и изменения
public static int Main(string[] args)
{
Employee p = new Employee();
p.SetFullName(“Fred");
Console. WriteLine( "Employee Is named: " + p. GetFullName());
// Ошибка! К закрытым данным нельзя обращаться напрямую
// через экземпляр объекта!
// p.FullName:
return 0;
}
Для обращения к внутренним данным можно использовать другой способ, а именно определить свойство.
Свойства
Свойство в C# состоит из двух блоков – блока доступа (get block) и блока изменения (set block).
Пример .
public class Employee
{
private int empID;//данные
// Свойство
public int EmpID
{
get{
return empID;
}
set{
empID=value;
}
}
}
public int getempID(){}//
public void setempID(int aa){empID=aa;}
static Main()
{
Employee stud=new Employee();
stud.EmpID=123;// можно и так: stud.setempID(123);
// На самом деле будет вызван stud.get_EmpID(123);
Console.WriteLine(stud.EmpID);// stud.getempID()
}
Обращаться к объекту value можно только в пределах программного блока set внутри определения свойства. Попытка обратиться к этому объекту из любого другого места приведет к ошибке компилятора.
Замечание.
Для внутреннего представления свойства используют методы с приставками get_ и set_, так в в нашем примере свойство автоматически будет отображено в методы get_EmpID() и set_EmpID().
Это мешает использованию для имен методов доступа и изменения привычных приставок get_ и set.
Если в свойстве оставить только блок get, то это свойство только для чтения.
using System;
namespace CSharpLessons
{
public class Square
{
private double _side;
// This is a new property
public double Side
{
get
{
return _side;
}
}
}
}
Можно определить поле только для чтения, используя ключевое слово readonly
public readonly string SSNfield;
Примеры . Из FunctionX. (The C_Sharp_Tutorials.doc), стр. 214-218.
Свойство для чтения
using System;
namespace CSharpLessons
{
public class DepartmentStore
{
private string itemNo;
private string cat;
private string name;
private string size;
private double price;
// A property for the stock number of an item
public string ItemNumber
{
Get
{
if( itemNo == "" )
return "Invalid Item";
else
return itemNo;
}
}
// A property for the category of item
public string Category
{
Get
{
if( cat == "" )
return "Unknown Category";
else
return cat;
}
}
// A property for an item's name of an item
public string ItemName
{
Get
{
if( name == "" )
return "Item no Description";
else
return name;
}
}
// A property for size of a merchandise
public string Size
{
get
{
if( size == "" )
return "Unknown Size or Fits All";
else
return size;
}
}
// A property for the marked price of an item
public double UnitPrice
{
Get
{
if( price == 0 )
return 0.00;
else
return price;
}
}
public DepartmentStore(string nbr,
string ctg,
string nme,
string siz,
double prc)
{
itemNo = nbr;
cat = ctg;
name = nme;
size = siz;
price = prc;
}
}
public class Exercise
{
static void Main()
{
DepartmentStore store = new DepartmentStore("53564",
"Men",
"Khaki Pants Sahara",
"34",
24.95);
int quantity = 4;
double totalPrice = store.UnitPrice * quantity;
Console.WriteLine("Customer Invoice");
Console.WriteLine("Item #: {0}", store.ItemNumber);
Console.WriteLine("Category: {0}", store.Category);
Console.WriteLine("Description: {0}", store.ItemName);
Console.WriteLine("Item Size: {0}", store.Size);
Console.WriteLine("Unit Price: {0}", store.UnitPrice.ToString("C"));
Console.WriteLine("Quantity: {0}", quantity);
Console.WriteLine("Total Price: {0}\n", totalPrice.ToString("C"));
}
}
}
Наследование
Главная задача наследования — обеспечить повторное использование кода. Существует два основных вида наследования: классическое наследование (отношение «быть» — is-a) и включение-делегирование (отношение «иметь» — has-a).
Основная идея классического наследования заключается в том, что производные классы должны получать функциональность от базового класса-предка и дополнять ее новыми возможностями.
В С# производный класс создается постановкой двоеточия после имени производного класса и указанием имени базового класса:
public class Sphere : Circle
В С# при создании производного класса в качестве базового класса можно указать только один класс.
Дата добавления: 2020-04-08; просмотров: 128; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!