Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

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

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

Пример:

#include <iostream.h>

class myclass {

    int a;

    public:

    myclass(int x); // конструктор

    void show();

};

myclass::myclass(int x)

{

    cout << "В конструкторе\n";

    a = x;

}

void myclass::show()

{

cout << a << "\n";

}

main()

{

    myclass ob(4);

    ob.show();

return 0;

}

Конструктор myclass имеет один параметр. Значение, передаваемое в myclass() используется для инициализации а. Аргумент 4 передается в ob(4) в качестве аргумента. Деструктор в отличие от конструктора параметров не имеет.

В данном примере конструктору мы передавали константы, но так же можно передавать переменные:

Пример:

include <iostream.h>

class myclass {

    int i, j;

    public:

    myclass(int a, int b);

    void show();

};

myclass::myclass(int a, int b)

{

    i = a;

    j = b;

}

void myclass::show()

{

    cout << i << ' ' << j << "\n";

}

main()

{

    int x, y;

cout << "Введите два целых: ";

cin >> x >> y;

// использование переменных для создания ob

    myclass ob(x, y);

    ob.show();

 return 0;

}

В программе рассмотрено важное свойство объектов. Они могут создаваться по мере необходимости.

 

Введение в наследование

Наследование - это механизм посредством которого один класс (производный) может наследовать свойства другого класса (базового).

Базовый класс определяет все качества, которые являются общими для всех прпоизводных классов.

Пример:

//Базовый класс

class B {

    int i;

    public:

    void set_i(int n);

    int get_i();

};

//Производный класс D

class D: public B {

    int j;

    public:

    void set_j(int n);

    int mul();

};

После имени класса D стоит двоеточие, за которым стоит ключевое слово public и имя класса B. Это означает, что класс D будет наследовать все компоненты класса B. Само ключевое слово public информирует компилятор о том, что т.к. B будет наследоваться, то все открытые элементы базового класса будут открытыми элементами производного класса. Однако все закрытые элементы базового класса остаются закрытыми.

Пример:

// Простой пример наследования.

#include <iostream.h>

// Задание базового класса

class base {

    int i;

    public:

    void set_i(int n);

    int get_i();

};

// Задание производного класса

class derived: public base {

    int j;

    public:

    void set_j(int n);

    int mul();

};

// Установка значения i в базовом классе

void base::set_i(int n)

{

    i = n;

}

// Возврат значения i в базовом классе

int base::get_i()

{

    return i;

}

// Установка значения j в производном классе

void derived::set_j(int n)

{

    j = n;

}

// Возврат значения i из base и, одновременно, j из derived

int derived::mul()

{

    // производный класс может вызывать функции-члены базового класса

    return j * get_i();

}

main()

{

    derived ob;

ob.set_i(10); // загрузка i в base

ob.set_j(4); // загрузка j в derived

    cout << ob.mul(); // вывод числа 40

return 0;

}

Важно! При определении mul() вызывается функция get_i()- базового класса B, а не производного D, что указывает на то, что открытые члены базового класса становятся открытыми членами производного. Но в функции mul() вместо прямого доступа к i, необходимо вызывать get_i(), потому что закрытые члены базового класса(i) остаются закрытыми для производных классов.

 

Виртуальные функции

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

#include <stdio.h>

class base {

public:

 int i;

 base(int x); //конструктор

 void func()

 {

 printf("Базовая функция %d",i);

 return;

 };

};

//текст конструктора

base::base(int x)

{

 i=x;

 return;

};

class der1: public base {

public:

 der1(int x):base(x) {}; //конструктор

 void func()

 {

 printf("Функция из производного класса %d", i*i);

 return;

 }

};

main()

{

 base * pc; //указатель на базовый класс

 base ob(2); //создать экземпляр объекта базового класса

 der1 ob1(2); //создать экземпляр объекта производного класса

 pc=&ob; //указатель на объект базового класса

 pc->func(); //вызов функции базового класса

 pc=&ob1; //указатель на объект производного класса

 pc->func(); //попытка вызова функции производного класса

 return 0;

 }

На первый взгляд, кажется, что в перврм случае будет вызываться функция базового класса, а во втором функция производного. Однако при проверке Вы легко убедитесь, что и в том и в другом случае будет вызвана функция функция базового класса. В чем тут дело? Дело в том, что компилятору трудно понять, какую реально функцию мы имеем в виду и он на стадии компилирования подставляет во всех тех случаях, где встречается имя func() адрес функции базового класса. Такой процесс установки адресов называется "ранним связыванием". Иногда употребляется термин "статическое связывание". Если же мы хотим, чтобы во втором случае, т.е. когда указатель pc указывал на производный класс вызывалась функция этого класса, ее еще в базовом классе следует указать как виртуальную. В нашем случае вместо строки void func() следует написать virtual void func(). После этого наш пример будет работать как надо.

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

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

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

#include <stdio.h>

class base {

public:

 int i;

 base(int x); //конструктор

 virtual void func()

 {

 printf("Базовая функция %d\n",i);

 return;

 };

};

//текст конструктора

base::base(int x)

{

 i=x;

 return;

};

class der1: public base {

public:

 der1(int x):base(x) {}; //конструктор

 void func()

 {

 printf("Функция из производного класса %d\n", i*i);

 return;

 }

};

class der2: public base {

public:

 der2(int x):base(x) {}; //конструктор

};

main()

{

 base * pc; //указатель на базовый класс

 base ob(2); //создать экземпляр объекта базового класса

 der1 ob1(2); //создать экземпляр объекта производного класса 1

 der2 ob2(2); //создать экземпляр объекта производного класса 2

 pc=&ob; //указатель на объект базового класса

 pc->func(); //вызов функции базового класса

 pc=&ob1; //указатель на объект производного класса 1

 pc->func(); //попытка вызова функции производного класса

 pc=&ob2; //указатель на объект производного класса 2

 pc->func(); //попытка вызова функции производного класса

 return 0;

 }

Как видите, мы ввели еще один производный класс. В нем функция func() не определена. В этом случае будет вызываться функция класса родителя. Т.е. появится строка: Базовая функция 2. Как видите принцип очень прост: если Вы хотите, чтобы вызывалась функция родительского класса, не определяйте ее в производном. Еще один вопрос может возникнуть в связи с данным примером: как быть, если мы хотим, чтобы для класса объектов der2 вызывалась функция класса der1. Решение очень просто - сделайте класс der2 наследником не класса base, а класса der1.

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

virtual void func() = 0;

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

 

Указатели на объекты

Доступ к члену объекта возможен не только через точку (.). Возможен доступ и через указатель на этот объект. В этом случае применяют стрелку (->).

Пример:

#include <iostream.h>

class myclass {

    int a;

    public:

    myclass(int x); // конструктор

    int get();

};

myclass::myclass(int x)

{

    a = x;

}

int myclass::get()

{

    return a;

}

main()

{

    myclass ob(120); // создание объекта

    myclass *p; // создание указателя на объект

p = &ob; // передача адреса ob в p

cout << "Значение, получаемое при использовании объекта:" << ob.get();

cout << "\n";

cout << "Значение, получаемое при использовании указателя:" << p->get();

return 0;

}

В программе объявление myclass *p создает указатель на объект myclass(а не создает объект!).

Для передачи адреса ob в p используется выражение p=&ob.

Для получения доступа к объекту через указатель используется выражение p->get();.


Глава 4. Основы программирование на языке C ++ Builder

4.1 Характеристика С++ Builder

 

С++ Builder – это дальнейшее развитие языка Си, основанное на системе быстрой разработки приложений RAD (Rapid Application Development).

В C++ Builder интегрирована Палитра компонент, разделенная картотечными вкладами на несколько функциональных страниц. Функциональные возможности компонент из страниц можно достаточно просто модифицировать, а также разрабатывать собственные компоненты.

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

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

C++ Builder поддерживает основные принципы объектно-ориентированного программирования - инкапсуляцию, полиморфизм и множественное наследование, а также нововведенные спецификации и ключевые слова в стандарте языка С++.

C++ Builder поддерживает связь с базами данных: dBASE, Paradox, Sybase, Oracle, InterBase, Informix, Exel, Access, FoxPro. Механизм BDE (Borland Database Engine) придает обслуживанию связей с базами данных простоту и прозрачность. Проводник Database Explorer позволяет изображать связи и объекты баз данных графически.

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

Профессиональные средства языка С++ интегрированы в визуальную среду разработки. C++ Builder предоставляет быстродействующий компилятор с языка Borland С++, инкрементальный загрузчик и средства отладки.

Конструирование по способу «drag-and-drop» позволяет создавать приложение простым перетаскиванием захваченных мышью визуальных компонент из палитры на форму приложения. Инспектор объектов предоставляет возможность оперировать со свойствами и событиями компонент, автоматически создавая заготовки функций обработки событий, которые наполняются кодом и редактируются в процессе разработки.

Механизмы двунаправленной разработки (two-way-tools) обеспечивает контроль за кодом посредством гибкого, интегрированного и синхронизированного взаимодействия между инструментами визуального программирования и Редактором кода.

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

Между программными продуктами С++ Builder и Borland C++ существует полная и взаимная функциональная совместимость.

Все компоненты, формы и модули данных, языка Delphi, могут быть повторно использованы в приложениях C++Builder без каких бы то ни было изменений.

C++ и Delphi равноправны - почти все, что написано в Delphi, можно использовать в C++Builder, и наоборот.

C++Builder не делает различия между тем, какие программные модули вы добавляете к проекту своего приложения - написаны они на C++ (файлы с расширением CPP) или на Delphi (файлы с расширением PAS). Компилятор свободно принимает следующие кодовые конструкции моделей Delphi 3.0: компоненты, формы, объекты, константы, простые методы и функции - все перечисленные коды можно прямо подставлять в свои проектные файлы. Технология визуального наследования форм дает возможность модифицировать формы Delphi в среде C++Builder без каких бы то ни было проблем.

 

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...