Реализация базового и производного классов.
Прежде всего конструкторы. В базовом использовался конструктор:
BankAccount::BankAccount(const char* s = "NULLBody",long an=-1,double bal = 0.0)
{
strncpy(fullName,s,MAX-1);
fullName[MAX-1] = '\0';
acctNum = an;
balance = bal;
}
При определении конструктора в производном классе надо думатьи об инициализации переменных заданых в базовом классе.
Надо помнить, что когда создаётся объект, то часть относящаяся к базовому классу создаётся и инициализируется раньше, чем часть производного и всегда раньше выполняется вызов конструктора базового класса! |
Если не указано иное, то вызывается конструктор по умолчанию для базового класса, а он нам не подходит. Поэтому применим список инициализации:
Overdraft::Overdraft(const char* s = "NULLBody",
long an,double bal , double ml,double r):BankAccount(s,an,bal)
{
maxLoan =ml;
owesBank =0.0;
rate =r;
}
Здесь указан вызов конструктора BankAccount к для инициализации компонент относящихся к базовому классу.
2-й конструктор используется для обеспечения возможности преобразования объектов типа BankAccount к типу Overdraft или что то же для создания объектов класса Overdraft на основе объектов класса BankAccount.
Overdraft::Overdraft(const BankAccount& ba, double ml,double r):BankAccount(ba)
{
maxLoan =ml;
owesBank =0.0;
rate =r;
}
Вспомним, что в классе BankAccount нет явного определения конструктора копирование. Его неявная реализация – копирование всех полей объекта, что в данном случае нас полне устраивает.
Метод Deposit наследуется из базового класса:
void BankAccount::Deposit(double amt)
{ balance+= amt;}
Метод Withdraw() определенен в базовом классе так:
void BankAccount::Withdraw(double amt)
{
if (amt<=balance) balance-=amt;
Else
cout<<”Withdrawal amount of $”<<amt
<<” exceeds your balance.\n”
<<” Withdrawal canceled.\n”;
}
В производном классе мы хотим определить этот метод несколько иначе. Он должен реализовывать защиту от превышения кредита с учётом возможности задолженности и отчислений в этом случае банку. В реализации учитываем, что не можем прямо обращаться к private – разделу базового класса:
void Overdraft::Withdraw(double amt)
{
double bal = Balance();
if (amt<=bal)
BankAccount::Withdraw(amt);
else if ((amt<=bal+maxLoan-owesBank)
{
double advance = amt_bal;
owesBank+=advance*(1.0+rate);
cout<<"Bank advance:$"<<advance<<endl;
cout<<"Finance charge:$"<<advance*rate<<endl;
Deposit(advance);
BankAccount::Withdraw(amt);
}
Else
cout<<"Credit limit eceeded. Transaction canceled.\n";
}
Метод Balance() наследуется:
double BankAccount::Balance() const
{return balance;}
Вывод: в производном классе можно обратиться к перекрытому методу базового класса используя синтаксис вида - Имя_класса::вызов метода. |
Совет: при возникновении коллизий к глобальным переменным можно обратиться используя имена вида: ::имя_переменной. |
Вопросы для самоконтроля
· Как выглядит список инициализаторов полей объекта в конструкторах?
· Как связаны операторы new и delete в конструкторах и деструкторах?
· Изложите суть наследования!
· Какие виды наследования применяются в С++7
· Как выглядят списки наследования?
· В каком порядке вызываются конструкторы объектов в случае применения наследования?
· Каким образом можно обратиться к перекрытым методам базовых классов из производного класса и к «перекрытым» глобальным переменным?
Вопросы для самостоятельного изучения
· Назначение атрибута доступа protected?
· Влияние атрибутов доступа в списке наследования на атрибуты доступа наследуемых элементов классов?
· Назначение ключевого слова virtual в списке наследования классов? (Обратите внимание на ситуацию множественного наследования и на существенное отличие от указания virtual для методов)
Лекция 23. С++: виртуальные функции-элементы, параметризация и новые операторы приведения типов данных
Дата добавления: 2016-05-26; просмотров: 1736;