在写程序时,若需定义多个类别(比如类别A、B、C),而类别B、C拥有类别A的某些资料成员、或某些成员方法,则我们可以使用继承让B/C直接获得A的public与protect部分,在C++中一般称呼A为基本类别,B与C为衍生类别,基本类别就是Java里的父类别而衍生类别就是子类别,C++真是一个麻烦的语言,在C++中类别分成public, protect, private三部分,继承也分为public, protect, private inheritance,我们主要探讨蚂蚁书的public inheritance中关於私有资料成员如何处理的范例:
如上图所示即使是public inheritance也无法存取父类别的private member(date and method),下面是父类别Employee的标头档可以看到有三个private date member,分别是firstName, lastName, socialSecurityNumber, 子类别是无法读取的
本日篇幅较多包含10个档案所以所有程序码都摆在day25_example
// Fig. 13.13: Employee.h
// Employee abstract base class.
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
#include <string> // C++ standard string class
using std::string;
class Employee
{
public:
Employee( const string &, const string &, const string & );
void setFirstName( const string & ); // set first name
string getFirstName() const; // return first name
void setLastName( const string & ); // set last name
string getLastName() const; // return last name
void setSocialSecurityNumber( const string & ); // set SSN
string getSocialSecurityNumber() const; // return SSN
// pure virtual function makes Employee abstract base class
virtual double earnings() const = 0; // pure virtual
virtual void print() const; // virtual
private:
string firstName;
string lastName;
string socialSecurityNumber;
}; // end class Employee
#endif // EMPLOYEE_H
类别CommissionEmployee的原始码.cpp档中可以发现子类别的print()方法中有一段呼叫父类别方法的代码Employee::print();,再去点开父类别的原始码.cpp档会发现父类别的print()方法会再call三个成员方法getFirstName(),getLastName(), getSocialSecurityNumber()。
// Fig. 13.14: Employee.cpp
// Abstract-base-class Employee member-function definitions.
// Note: No definitions are given for pure virtual functions.
#include <iostream>
using std::cout;
#include "Employee.h" // Employee class definition
// constructor
Employee::Employee( const string &first, const string &last,
const string &ssn )
: firstName( first ), lastName( last ), socialSecurityNumber( ssn )
{
// empty body
} // end Employee constructor
// set first name
void Employee::setFirstName( const string &first )
{
firstName = first;
} // end function setFirstName
// return first name
string Employee::getFirstName() const
{
return firstName;
} // end function getFirstName
// set last name
void Employee::setLastName( const string &last )
{
lastName = last;
} // end function setLastName
// return last name
string Employee::getLastName() const
{
return lastName;
} // end function getLastName
// set social security number
void Employee::setSocialSecurityNumber( const string &ssn )
{
socialSecurityNumber = ssn; // should validate
} // end function setSocialSecurityNumber
// return social security number
string Employee::getSocialSecurityNumber() const
{
return socialSecurityNumber;
} // end function getSocialSecurityNumber
// print Employee's information
void Employee::print() const
{
cout << getFirstName() << ' ' << getLastName()
<< "\nsocial security number: " << getSocialSecurityNumber();
} // end function print
在CommissionEmployee的标头档可以发现确实没有定义firstName, lastName, socialSecurityNumber三个资料成员与getFirstName(),getLastName(), getSocialSecurityNumber()三个成员方法,现在好玩的来了!如果再多一个子类别:佣金+底薪员工去继承佣金员工CommissionEmployee会怎样呢? 老样子直接点开BasePlusCommissionEmployee的标头档与与原始码.cpp,可以惊人的发现BasePlusCommissionEmployee的成员方法print()直接呼叫CommissionEmployee::print();也没有去定义所需的成员方法与资料。这就是继承的核心大量的程序码复用reuse。
最後点开主程序fig13_25.cpp,可以看出父类别Employee有三个子类别SalariedEmployee, HourlyEmployee, CommissionEmployee与一个孙类别BasePlusCommissionEmployee,首先创造一个Employee类别指标向量vector < Employee * > employees( 4 ); 由於四个类别都继承自Employee所以可以直接摆到Employee类别指标向量中,接着透过for回圈逐一呼叫print()方法成员,这里有个Tricky,因为我们前面使用的是指标所以是必须使用->如employees[i]->print();而非.(dot) 呼叫成员方法,而回到typeid时就不再是指标所以用.(dot) 如typeid( *employees[j] ).name() << endl;
<<: #21-用Canvas做科技感的动态球!(+什麽时候该用CSS/SVG/Canvas?)
我们在定义类别或结构时,有时候会需要做初始化的动作,简单说,就是给一个值,譬如我们在写C的时候,如果...
接着来讲讲get set部分.... public class A { public string ...
在多文字档中搜寻关键字 第一层for回圈使用了os.walk()递回取得路径下的所有档案 第二层fo...
不过有些需要下的指令可不能省喔~ .env APP_NAME=Laravel APP_ENV=loc...
p段落标签最常使用搭配段落文章使用 同时也是一个display:block特性的元素 <p&g...