Симон Робинсон - C# для профессионалов. Том II
В C# можно объявить абстрактную функцию, также как это делается в C++ (в C++ она называются еще чисто виртуальной функцией), но в C# синтаксис будет отличаться: вместо использования =0 в конце определения применяется ключевое слово abstract.
C++:
public:
virtual void DoSomething(int X) = 0;
C#:
public abstract void Dosomething(int X);
Как и в C++, можно создать экземпляр класса, только если он сам не содержит абстрактных методов и предоставляет реализации всех абстрактных методов, которые были определены в любом из его базовых классов.
Структуры
Синтаксис определения структур в C# соответствует синтаксису определения классов.
struct MyStruct {
private SomeField;
public int SomeMethod() {
return 2;
}
}
Наследование и связанные концепции, виртуальные и абстрактные функции не допускаются. В остальном базовый синтаксис идентичен синтаксису классов, за исключением того, что ключевое слово struct заменяет в определении class.
Существуют, однако, различия между структурами и массами, когда дело доходит до создания. В частности, структуры всегда имеют конструктор по умолчанию, который обнуляет все поля, и этот конструктор по-прежнему присутствует, даже если определены другие собственные конструкторы. Также невозможно явно определить конструктор без параметров для замены конструктора по умолчанию. Можно определить только конструкторы с параметрами. В этом отношении структуры в C# отличаются от своих аналогов в C++.
В отличие от классов в C#, структуры являются типом данных значений. Это означает, что такая инструкция как:
MyStruct Mine;
реально создает экземпляр MyStruct в стеке. Однако в C# этот экземпляр не инициализируется, если конструктор не вызван явно:
MyStruct Mine = new MyStruct();
Если все поля-члены из MyStruct являются открытыми, можно альтернативно инициализировать структуру, преобразуя каждое поле-член по отдельности.
Константы
Ключевое слово const в C++ имеет достаточно большой диапазон использования. Например, можно объявить переменные как const, тем самым указывая, что их значения обычно задаются во время компиляции и не могут изменяться никакой инструкцией присваивания во время выполнения (хотя существует небольшой элемент гибкости, так как значение члена переменной const может быть задано в списке инициализации конструктора, а это предполагает в данном случае, что значение может вычисляться во время выполнения). Можно также применять const к указателям и ссылкам, чтобы запретить их использование для изменения данных, на которые они указывают, и можно также использовать ключевое слово const для модификации определений параметров, передаваемых в функции. В этом случае const показывает, что переменная, которая была передана по ссылке или через указатель, не должна изменяться функцией. Как упоминалось ранее, сами члены функции тоже могут быть объявлены как const, чтобы подчеркнуть, что они не изменяют содержащий их экземпляр класса.
C# позволяет также использовать ключевое слово const для указания, что переменная не может изменяться. Во многих отношениях, однако, применение const более ограничено в C#, чем в C++. В C# единственное использование const состоит в фиксировании значения переменной (или элемента, на который указывает ссылка) во время компиляции. Оно не может применяться к методам или параметрам. С другой стороны, C# имеет преимущества перед C++ в том смысле, что синтаксис в C# допускает немного больше гибкости при инициализации полей const во время выполнения.
Синтаксис объявления констант различается в C# и C++, поэтому мы рассмотрим его более подробно. Синтаксис C# использует два ключевых слова — const и readonly. Ключевое слово const предполагает, что значение задается во время компиляции, в то время как readonly предполагает, что оно задается однажды во время выполнения в конструкторе.
Так как все в C# должно быть членом класса или структуры, не существует, конечно, прямого эквивалента в C# для глобальных констант C++. Эту функциональность можно получить с помощью перечислений или статических полей-членов класса.
Константы, ассоциированные с классом (статические константы)
Обычный способ определения статической константы в C++ состоит в записи члена класса как static const. C# делает это похожим образом, но с помощью более простого синтаксиса:
Синтаксис C++:
int CMyClass::MyConstant = 2;
class CMyClass {
public:
static const int MyConstant;
Синтаксис C#:
class MyClass {
public const int MyConstant = 2;
Отметим, что в C# константа не определяется явно как static, если это сделать, то возникнет ошибка компиляции. Она является, конечно, неявно статической, так как не существует возможности задать значение константы более одного раза, и, следовательно, она всегда должна быть доступна как статическое поле.
int SomeVariable = MyClass.MyConstant;
Ситуация становится интереснее, если статическую константу инициализировать некоторым значением, которое вычисляется во время выполнения. C++ не имеет средств, чтобы это сделать. Для достижения такого результата потребуется найти некоторые возможности инициализировать переменную при первом обращении к ней, что означает, что ее прежде всего невозможно объявить как const. В случае C# статические константы инициализируются во время выполнения. Поле определяется как readonly и инициализируется в статическом конструкторе.
class MyClass {
public static readonly int MyConstant;
static MyClass() {
// определяет и присваивает начальное значение MyConstant
}
Константы экземпляра
Константы, которые ассоциированы с экземплярами класса, всегда инициализируются значениями, вычисленными во время выполнения. (Если их значения были вычислены во время компиляции, то, по определению, это делает их статическими.)
В C++ такие константы должны быть инициализированы в списке инициализации конструктора класса. Это в некоторой степени ограничивает гибкость при вычислении значений этих констант, так как начальное значение должно быть таким, чтобы его можно было записать как выражение в списке инициализации конструктора.
class CMyClass {
public:
const int MyConstInst;
CMyClass() : MyConstInst(45); {
В C# принцип похож, но константа объявляется как readonly, а не как const. Таким образом, ее значение задается в теле конструктора, придавая гибкость процессу, так как можно использовать любые инструкции C# при вычислении начального значения. (Вспомните, что в C# невозможно задать значения переменных в инициализаторе конструктора, только вызвать другой конструктор.)
class MyClass {
public readonly int MyConstInst;
MyClass() {
// определяет и инициализирует здесь MyConstInst
Если поле в C# объявлено как readonly, то ему можно присвоить значение только в конструкторе.
Перезагрузка операторов
Перезагрузка операторов происходит в C# и в C++ аналогично, но существуют небольшие различия. Например, C++ допускает перезагрузку большинства своих операторов. C# имеет больше ограничений. Для многих составных операторов C# автоматически определяет значение оператора из значений составляющих операторов, т.е. там, где C++ допускает прямую перезагрузку. Например, в C++ перезагружается + и отдельно +=. В C# можно перезагрузить только +. Компилятор всегда будет использовать перезагруженную версию +, чтобы автоматически определить значение += для этого класса или структуры.
Следующие операторы могут перезагружаться в C# также, так и в C++:
□ Бинарные арифметические операторы +, -, *, /, %
□ Унарные операторы ++ и -- (только префиксная форма)
□ Операторы сравнения !=, ==, <, <=, >=
□ Побитовые операторы &, |, ~, ^, !
□ Булевы значения true и false
Следующие операторы, перезагружаемые в C++, нельзя перезагружать в C#.
□ Арифметические операторы присваивания *=, /=, +=, -=, %=. (Они определяются компилятором из соответствующих арифметических операторов и оператора присваивания, который не может перезагружаться.) Постфиксные операторы увеличения на единицу. Они определяются компилятором из перезагруженных версий соответствующих префиксных операторов. (Реализуются с помощью вызова соответствующей перезагруженной версии префиксного оператора, но возвращают первоначальное значение операнда вместо нового значения.)