Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Gosy_nepolnostyu_7v1.doc
Скачиваний:
2
Добавлен:
01.07.2025
Размер:
3.7 Mб
Скачать

Abstract Class Example:

Consider the following example where parent class provides an interface to the base class to implement a function called getArea():

#include <iostream> using namespace std; // Base class class Shape { public:   // pure virtual function providing interface framework.   virtual int getArea() = 0;   void setWidth(int w)   {      width = w;   }   void setHeight(int h)   {      height = h;   } protected:   int width;   int height; }; // Derived classes class Rectangle: public Shape { public:   int getArea()   {      return (width * height);   } }; class Triangle: public Shape { public:   int getArea()   {      return (width * height)/2;   } }; int main(void) {   Rectangle Rect;   Triangle  Tri;   Rect.setWidth(5);   Rect.setHeight(7);   // Print the area of the object.   cout << "Total Rectangle area: " << Rect.getArea() << endl;   Tri.setWidth(5);   Tri.setHeight(7);   // Print the area of the object.   cout << "Total Triangle area: " << Tri.getArea() << endl;   return 0; }

Интерфейс содержит определения для группы определенного функционала, который класс или структура могут реализовывать

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

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

interface IEquatable<T> {    bool Equals(T obj); }

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

C#

class Test {    static void Main()    {        SampleClass sc = new SampleClass();        IControl ctrl = (IControl)sc;        ISurface srfc = (ISurface)sc;        // The following lines all call the same method.        sc.Paint();        ctrl.Paint();        srfc.Paint();    } } interface IControl {    void Paint(); } interface ISurface {    void Paint(); } class SampleClass : IControl, ISurface {    // Both ISurface.Paint and IControl.Paint call this method.    public void Paint()    {        Console.WriteLine("Paint method in SampleClass");    } } // Output: // Paint method in SampleClass // Paint method in SampleClass // Paint method in SampleClass

(http://www.tutorialspoint.com/cplusplus/cpp_interfaces.htm, https://msdn.microsoft.com/ru-ru/library/ms173156.aspx, https://msdn.microsoft.com/ru-ru/library/ms173157.aspx)

15. Наследование классов, на примере языков С++ и С#.

(Туривный С.)

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

class employee

{

public:

  employee(char *, char *, float);

  void show_employee(void);

private:

  char name[64];

  char position[64];

  float salary;

};

Далее предположим, что вашей программе требуется класс manager, который добавляет следующие элементы данных в класс employee:

float annual_bonus;

char company_car[64];

int stock_options;

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

Для определения этого класса вы должны указать ключевое слово class, имя manager, следующее за ним двоеточие и имя employee, как показано ниже:

Производный класс //-----> class manager : public employee { <-------// Базовый класс

// Здесь определяются элементы

};

Ключевое слово public, которое предваряет имя класса employee, указывает, что общие (public) элементы класса employee также являются общими и в классе manager. Например, следующие операторы порождают класс manager.

class manager : public employee

{

public:

  manager(char *, char *, char *, float, float, int);

  void show_manager(void);

private:

  float annual_bonus;

  char company_car[64];

  int stock_options;

};

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

В языке C# класс, который наследуется, называется базовым, а класс, который наследует, — производным. Следовательно, производный класс представляет собой специализированный вариант базового класса. Он наследует все переменные, методы, свойства и индексаторы, определяемые в базовом классе, добавляя к ним свои собственные элементы.

Поддержка наследования в C# состоит в том, что в объявление одного класса разрешается вводить другой класс. Для этого при объявлении производного класса указывается базовый класс. При установке между классами отношения "является" строится зависимость между двумя или более типами классов. Базовая идея, лежащая в основе классического наследования, заключается в том, что новые классы могут создаваться с использованием существующих классов в качестве отправной точки:

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 {    class ProfessorWeb    {        const string ADDR = "http:\\professorweb.ru";        public string level, inLevel;        public int numberSt;        private string inf;        public void InfoPW()        {            Console.WriteLine("Сайт: {0}\nРаздел: {1}\nПодраздел: {2}\nКол-во статей:{3}",ADDR,level,inLevel,numberSt);        }    }    // Объявляем класс, унаследованный от класса ProfessorWeb    class CSharp : ProfessorWeb    {        public string st;        // Поля класса ProfessorWeb доступны через конструктор наследуемого класса        public CSharp(string level, string inLevel, int numberSt, string st)        {            this.level = level;            this.inLevel = inLevel;            this.numberSt = numberSt;            this.st = st;        }        public void StWrite()        {            Console.WriteLine("Статья: "+st);        }    }    class Program    {        static void Main()        {            CSharp obj = new CSharp(level: "C#", inLevel: "Перегрузка", numberSt: 7, st: "Перегрузка методов");            obj.InfoPW();            obj.StWrite();            Console.ReadLine();        }    } }

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

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

Для любого производного класса можно указать только один базовый класс. В C# не предусмотрено наследование нескольких базовых классов в одном производном классе. (В этом отношении C# отличается от С++, где допускается наследование нескольких базовых классов. Данное обстоятельство следует принимать во внимание при переносе кода С++ в C#.) Тем не менее можно создать иерархию наследования, в которой производный класс становится базовым для другого производного класса. (Разумеется, ни один из классов не может быть базовым для самого себя как непосредственно, так и косвенно.) Но в любом случае производный класс наследует все члены своего базового класса, в том числе переменные экземпляра, методы, свойства и индексаторы.

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

Подробнее здесь - http://professorweb.ru/my/csharp/charp_theory/level7/7_1.php

(http://programmersclub.ru/26/, http://professorweb.ru/my/csharp/charp_theory/level7/7_1.php)

16. Преобразование данных, на примере языков С++ и С#.

(Туривный С.)

В C++ различают явное и неявное преобразование типов данных. Неявное преобразование типов данных выполняет компилятор С++, ну а явное преобразование данных выполняет сам программист. О преобразовании типов данных скажу следующее: «Результат любого вычисления будет преобразовываться к наиболее точному типу данных, из тех типов данных, которые участвуют в вычислении». Для наглядного примера представлю таблицу с преобразованиями типов данных. В таблице рассмотрим операцию деления. В качестве целочисленного типа данных возьмем int, ну и вещественный тип данных у нас будет float.

x

y

Результат деления

Пример

делимое

делитель

частное

x = 15 y = 2

int

int

int

15/2=7

int

float

float

15/2=7.5

float

int

float

15/2=7.5

Еще один способ явного преобразования типов данных:

1

2

float(15) / 2    // результат равен 7.5, число 15 преобразуется в вещественный тип данных float.

double(15) / 2 // результат равен 7.5 – тоже самое!!!

В С++ также предусмотрена унарная операция приведения типа:

1

static_cast</*тип данных*/>(/*переменная или число*/)

пример: static_cast<float>(15)/2 результат равен 7.5

Пример с переменной:

1

2

int ret=15;

static_cast<float>(ret)/2 //результат равен 7.5

В случае с переменной надо понимать, что в строке 2 переменная ret не преобразуется в тип данных float, а всего лишь на всего создается временная копия переменной ret с типом данных float. Рассмотрим на практике все способы явного и неявного преобразования типов данных.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

// pryeobrazovanie.cpp: определяет точку входа для консольного приложения.

#include "stdafx.h"

#include <iostream>

#include <iomanip>

using namespace std;

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

{

   int int_value15 = 15, int_value2 = 2; // объявляем две переменные типа int

   float float_value15 = 15, float_value2 = 2; // объявляем две переменные типа float

   cout << fixed << setprecision(2) // определяем, при выводе чисел с плавающей точкой, два знака после запятой

        << "15   / 2   = " << int_value15   / int_value2   << endl  //неявное преобразование типов данных

        << "15   / 2   = " << int_value15   / float_value2 << endl  //неявное преобразование типов данных

        << "15   / 2   = " << float_value15 / int_value2   << endl  //неявное преобразование типов данных

        << "15   / 2   = " << float_value15 / float_value2 << endl; //неявное преобразование типов данных

   cout << "15.0 / 2   = " << 15.0 / 2 << endl  // явное преобразование типа данных, число 15.0 - число с плавающей точкой

        << "15   / 2.0 = " << 15 / 2.0 << endl; // явное преобразование типа данных, число 2.0  - число с плавающей точкой

   cout << "float(int_value15) / int_value2 = " << float(int_value15) / int_value2 << endl // явное преобразование типа данных

        << "15 / double(2) = " << 15 / double(2) << endl;                                    // используя приводимый тип как функцию

   cout << "static_cast<float>(15) / 2 = " << static_cast<float>(15) / 2 << endl // унарная операция приведения типа

        << "static_cast<char>(15) = " << static_cast<char>(15) << endl  // можно печатать различные символы из таблицы ASCII,

        << "static_cast<char>(20) = " << static_cast<char>(20) << endl; // в скобочках прописываем код символа, который находим в таблице ASCII

   system("pause");

   return 0;

}

static_cast — унарная операция приведения типов данных в С++

Операция static_cast доступна только в языке C++. static_cast может быть использована для преобразования одного типа в другой, но она не должна быть использована для выполнения недопустимого преобразования, например, преобразование значения в указатель или наоборот. Рекомендуется пользоваться операцией static_cast, нежели Cи-стилем приведения, потому что static_cast ограничивает недопустимое приведение типов и, следовательно — безопаснее.

Операция static_cast, грубо говоря, — это шаблон функции, в которой необходимо явно указать  тип данных для преобразования, то есть задать параметр шаблона.

1

static_cast<dataType>(value);

Итак, в треугольных скобочках указывается тип данных, к которому необходимо преобразовать значение value, которое стоит в круглых скобочках. Смотрим все тот же пример, который приводит int к типу double для того, чтобы при делении 13-ти на 7 избежать усечения результата из-за целочисленного деления.

1

double res = static_cast<double>(13)/7;

dynamic_cast — унарная операция приведения типов данных в С++

Операция dynamic_cast доступна только в C++ и имеет смысл только, применительно к членам класса иерархии «полиморфных типов». Динамическое приведение типов данных может быть использовано для безопасного приведения указателя (или ссылки) на суперкласс, в указатель (или ссылку) на подкласс в иерархии классов. Если динамическое приведение типов — недопустимо, так как реальный тип объекта, указывает не на тот тип подкласса, приведение типов не выполнится.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]