類的繼承與派生

一融撞、類的繼承與類的派生

繼承的概念

通過已有的類建立新類的過程,叫做類的派生粗蔚。

原來的類稱為基類尝偎,也稱為父類或一般類;新類稱為派生類鹏控,也稱為子類或特殊類致扯。

派生類的定義與大小

派生類的定義

在C++語言中,從基類派生派生類的格式

class 派生類名 : 繼承方式說明符 基類名
{
  類體
};

繼承方式說明符指明如何控制基類成員在派生類中的訪問屬性当辐,通常有public抖僵、private和protected 3中方式。

例5-1 基類與派生類的定義

class BaseClass         //基類 
{
    int v1,v2;
};

class DerivedClass:public BaseClass     //派生類 
{
    int v3;
 };

空類也可以作為基類缘揪。

程序5-1 派生類該百年基類成員的訪問權(quán)限

#include <iostream>
using namespace std;

class BaseClass
{
    public:
        int v1,v2;
        BaseClass():v1(1),v2(1){}
        int temp1(){}
};
 
class DerivedClass:public BaseClass
{
    int v1;
    int temp1(){}
    public:
        DerivedClass():v1(10){}
        void printv()
        {
            cout<<"v1="<<v1<<endl;
            cout<<"Base.v1="<<BaseClass::v1<<endl;
        }
};

int main()
{
    BaseClass bc;
    DerivedClass dc;
    dc.printv();
    return 0;
}

v1=10
Base.v1=1

類的大小

派生類大小占用的存儲空間大小耍群,等于基類成員變量占用的存儲空間大小加上派生類大小自身成員變量占用的存儲空間大小义桂。可以使用sizeof()函數(shù)計(jì)算大小占用的字節(jié)數(shù)蹈垢。

為類大小分配空間時慷吊,遵循字節(jié)對齊的原則,空類的大小是1曹抬,這是一種特殊情況溉瓶。

對象占用的存儲空間包含對象中各成員變量占用的存儲空間。對象的大小與普通成員變量有關(guān),與成員函數(shù)和類中的靜態(tài)成員變量無關(guān)沐祷,即普通成員函數(shù)嚷闭、靜態(tài)成員函數(shù)、靜態(tài)成員變量赖临、靜態(tài)常量成員變量等均對類對象的大小沒有影響胞锰。

程序5-2 基類與子類占用空間及字節(jié)對齊

#include <iostream>
using namespace std;

class BaseClass
{
    int v1,v2;
    char v4;
    public:
        int temp1(){}
};
 
class DerivedClass:public BaseClass
{
    int v3;
    int *p;
    public:
        int temp(){}
};

int main()
{
    cout<<"Base="<<sizeof(BaseClass)<<endl;
    cout<<"Derived="<<sizeof(DerivedClass)<<endl; 
    return 0;
}

Base=12
Derived=24

繼承關(guān)系的特殊性

如果基類有友元類或友元函數(shù),則其派生類不會因繼承關(guān)系而也有此友元類或友元函數(shù)兢榨。

如果基類是某類的友元嗅榕,則這種友元關(guān)系是被繼承的。即被派生類繼承過來的成員函數(shù)吵聪。

如果原來是基類的友元函數(shù)凌那,那么它作為派生類的成員函數(shù)仍然是某類的友元函數(shù)。

基類的友元不一定是派生類的友元吟逝;基類的成員函數(shù)是某類的友元函數(shù)帽蝶,則其作為派生類繼承的成員函數(shù)仍是某類的友元函數(shù)。

程序5-3 派生類繼承了友元函數(shù)

#include <iostream>
using namespace std;

class another;      //前向引用聲明 
class Base      //基類 
{
    private:
        float x;
    public:
        void print(const another &K);
};

class Derived:public Base   //派生類 
{
    private:
        float y;
};

class another
{
    private:
        int aaa;
    public:
        another()
        {
            aaa = 100;
        }
        friend void Base::print(const another &K);
};

void Base::print(const another &K)
{
    cout<<"Base:"<<K.aaa<<endl;
}

int main()
{
    Base a;
    Derived d;
    another ano;
    a.print(ano);
    d.print(ano);
    return 0;
}

Base:100
Base:100

如果派生類Derived中重寫了print()函數(shù)块攒,若還想在函數(shù)中訪問another的私有成員励稳,則必須將類Derived的print()函數(shù)也聲明為another的友元。

程序5-4 派生關(guān)系中的靜態(tài)成員

#include <iostream>
using namespace std;
class Base
{
    private:
        float x;
    public:
        static int staV;
        Base()
        {
            staV++;
        }
};

int Base::staV = 0;

class Derived:public Base
{
    private:
        float y;
    public:
        Derived()
        {
            staV++;
        }
};

int main()
{
    Base a;
    cout<<a.staV<<endl;
    Derived d;
    cout<<d.staV<<endl;
    return 0;
}

1
3

有繼承關(guān)系的類之間的訪問

在類的派生層次結(jié)構(gòu)中囱井,基類的成員和派生類新增的成員都具有類作用域驹尼。二者的作用范圍不同,是相互包含的兩個層庞呕,派生類在內(nèi)層新翎,基類在外層。

程序5-5 訪問基類和派生類成員的方式

#include <iostream>
using namespace std;

class CB
{
    public:
        int a;
        CB(int x)
        {
            a = x;
        }
        void showa()
        {
            cout<<"Class CB--a="<<a<<endl;
        }
};

class CD:public CB
{
    public:
        int a;
        CD(int x,int y):CB(x)
        {
            a = y;
        }
        void showa()
        {
            cout<<"Class CD--a="<<a<<endl;
        }
        void print2a()
        {
            cout<<"a="<<a<<endl;
            cout<<"CB:a="<<CB::a<<endl;
        }
};

int main()
{
    CB CBobj(12);
    CBobj.showa();
    CD CDobj(48,999);
    CDobj.showa();
    CDobj.CB::showa();
    cout<<"CDobj.a="<<CDobj.a<<endl;
    cout<<"CDobj.CB::a="<<CDobj.CB::a<<endl;
}

Class CB--a=12
Class CD--a=999
Class CB--a=48
CDobj.a=999
CDobj.CB::a=48

程序5-6 類之間的訪問示例

#include <iostream>
#include <string>
using namespace std;

class CStudent
{
    private:
        string name;        //姓名 
        string id;          //學(xué)號 
        char gender;        //性別住练,'F'代表女生地啰,'M'代表男生 
        int age;            //年齡 
    public:
        void PrintInfo();
        void SetInfo(const string &,const string &,int,char);
        void SetName(string);
        string GetName();
        void SetId(string);
        string GetId();
};

void CStudent::PrintInfo()
{
    cout<<"姓名:\t"<<name<<endl;
    cout<<"學(xué)號:\t"<<id<<endl;
    cout<<"年齡:\t"<<age<<endl;
    cout<<"性別:\t"<<gender<<endl; 
}

void CStudent::SetInfo(const string & name_,const string & id_,int age_,char gender_)
{
    name = name_;
    id = id_;
    age = age_;
    gender = gender_; 
}
void CStudent::SetName(string name)
{
    this->name = name;
}

string CStudent::GetName()
{
    return name;
}

void CStudent::SetId(string id)
{
    this->id = id;
}

string CStudent::GetId(){
    return id;
}

class CUndergraduateStudent:public CStudent     //本科生類,繼承于類CStudent 
{
    private:
        string department;      //學(xué)生所屬的系名
    public:
        void PrintInfo();
        void SetInfo(const string &,const string &,int,char,const string &); 
};

void CUndergraduateStudent::PrintInfo()
{
    CStudent::PrintInfo();  //調(diào)用基類的公有PrintInfo函數(shù)
    cout<<"院系:\t"<<department<<endl<<endl;  //訪問的是本派生類的成員變量 
}
void CUndergraduateStudent::SetInfo(const string & name_,const string & id_,int age_,char gender_,const string & department_)
{
    CStudent::SetInfo(name_,id_,age_,gender_);  //調(diào)用基類的公有SetInfo函數(shù)
    department = department_; 
}

class CGraduatedStudent:public CStudent     //研究生類,繼承于類CStudent 
{
    private:
        string department;
        string advisor;     //導(dǎo)師
    public:
        void PrintInfo();
        void  SetInfo(const string & name_,const string & id_,int age_,char gender_,const string & department_,const string & advisor_);
};

void CGraduatedStudent::PrintInfo()
{
    CStudent::PrintInfo();
    cout<<"院系:\t"<<department<<endl;
    cout<<"導(dǎo)師:\t"<<advisor<<endl<<endl; 
} 

void  CGraduatedStudent::SetInfo(const string & name_,const string & id_,int age_,char gender_,const string & department_,const string & advisor_)
{
    CStudent::SetInfo(name_,id_,age_,gender_);
    department = department_;
    advisor = advisor_;
}

int main()
{
    CStudent s1;
    CUndergraduateStudent s2;
    CGraduatedStudent s3;
    s2.SetInfo("小張","2018-6-2-4",19,'M',"數(shù)學(xué)系");
    s3.SetInfo("小李","M2017-9",23,'F',"計(jì)算機(jī)學(xué)院","孟教授");
    s2.PrintInfo();
    s3.PrintInfo();
//  cout<<s2.name<<endl;
//  s2.name = "張一";
    cout<<s2.GetName()<<endl;
    s2.SetName("張一");
    s2.PrintInfo();
    cout<<s2.GetName()<<","<<s2.GetId()<<endl;
    return 0; 
}
 

姓名:  小張
學(xué)號:  2018-6-2-4
年齡:  19
性別:  M
院系:  數(shù)學(xué)系

姓名:  小李
學(xué)號:  M2017-9
年齡:  23
性別:  F
院系:  計(jì)算機(jī)學(xué)院
導(dǎo)師:  孟教授

小張
姓名:  張一
學(xué)號:  2018-6-2-4
年齡:  19
性別:  M
院系:  數(shù)學(xué)系

張一,2018-6-2-4

程序5-7 類之間的訪問
假設(shè)公司雇員分為雇員(employee)讲逛、經(jīng)理(manager)髓绽、工程師(engineer)和高級主管(director)。各類的屬性如下:

employee(雇員)類:姓名妆绞、年齡顺呕、工資;

manager(經(jīng)理)類:姓名、年齡括饶、工資株茶、行政級別;

engineer(工程師)類:姓名、年齡图焰、工資启盛、專業(yè)、學(xué)位:

director(高級主管)類:姓名技羔、年齡僵闯、工資、行政級別藤滥、職務(wù)鳖粟。

將類employee 設(shè)計(jì)為基類,含有成員變量:姓名拙绊、年齡和工資向图。類manager 和類 engineer 是類employee的派生類,類director是類manager的派生類标沪。

#include <iostream>
#include <string>
using namespace std;

class employee          //類employee將作為其他幾個類的基類 
{
    short age;
    float salary;
    protected:
        string name;
    public:
        employee(short ag,float sa,string na)
        {
            age = ag;
            salary = sa;
            name = na;
        };
        void print()
        {
            cout<<"\n"<<name<<":\t";
            cout<<age<<":\t";
            cout<<salary;
        }
        ~employee(){}
};

class manager:public employee       //派生類 
{
    int level;
    public:
        manager(short ag,float sa,string na,int lev):employee(ag,sa,na) //對基類初始化 
        {
            level = lev;
        }
        void print()
        {
            employee::print();
            cout<<"\tlevel:"<<level;
        }
};

class engineer:public employee
{
    char speciality,adegree;
    public:
        engineer(short ag,float sa,string na,char spe,char ade):employee(ag,sa,na)
        {
            speciality = spe;
            adegree = ade;
        }
        void print()
        {
            employee::print();
            cout<<"\tspeciality:"<<speciality;
            cout<<"\tadegree:"<<adegree;
        }
};

enum ptitle {PS,GM,VPS,VGM};

class director:public manager
{
    ptitle post;
    public:
        director(short ag,float sa,string na,int le,ptitle po):manager(ag,sa,na,le)
        {
            post = po;
        }
        void print()
        {
            manager::print();
            cout<<"\tpost:"<<post<<endl;
        }
};

int main()
{
    employee emp1(23,610.5,"wang"),emp2(27,824.75,"li");
    manager man1(32,812.45,"zhang",11),man2(34,1200.5,"chen",7);
    engineer eng(26,1420.10,"sun",'E','M');
    director dir(38,1800.2,"liu",2,VPS);
    emp1.print();
    emp2.print();
    man1.print();
    man2.employee::print();
    eng.print();
    dir.print(); 
}

wang:   23:     610.5
li:     27:     824.75
zhang:  32:     812.45  level:11
chen:   34:     1200.5
sun:    26:     1420.1  speciality:E    adegree:M
liu:    38:     1800.2  level:2 post:2

protected訪問范圍說明符

基類中的保護(hù)成員可以在派生類的成員函數(shù)中被訪問榄攀。

程序5-8 基類中的成員是私有成員時的訪問方式

#include <iostream>
using namespace std;

class BaseClass
{
    int v1,v2;      //私有成員變量
    public:
        void SetValue(int m,int n)
        {
            v1 = m;
            v2 = n;
         } 
         void PrintValue();
};

void BaseClass::PrintValue()
{
    cout<<"v1="<<v1<<"\tv2="<<v2;
}
class DerivedClass:public BaseClass
{
    int v3;
    public:
        void SetValue(int m,int n,int k)
        {
            BaseClass::SetValue(m,n);
            v3 = k;
        }
        void PrintValue();
};

void DerivedClass::PrintValue()
{
    cout<<endl;
    BaseClass::PrintValue();
    cout<<"\tv3="<<v3<<endl;
}

int main()
{
    BaseClass baseCla;
    DerivedClass derivedCla;
    cout<<"初始時的隨機(jī)值:  "<<endl;
    baseCla.PrintValue();
    derivedCla.PrintValue();
    cout<<"修改基類中的值后:  "<<endl;
    baseCla.SetValue(10,20);
    baseCla.PrintValue();
    derivedCla.PrintValue();
    cout<<"從派生類修改從基類繼承的值及本類的值:  "<<endl;
    derivedCla.SetValue(100,200,300);
    baseCla.PrintValue();
    derivedCla.PrintValue();
    return 0; 
}

初始時的隨機(jī)值:
v1=0    v2=0
v1=0    v2=0    v3=19
修改基類中的值后:
v1=10   v2=20
v1=0    v2=0    v3=19
從派生類修改從基類繼承的值及本類的值:
v1=10   v2=20
v1=100  v2=200  v3=300

程序5-9 基類中保護(hù)成員的訪問方式

#include <iostream>
using namespace std;

class BaseClass
{
    protected:
        int v1,v2;
    public:
    void SetValue(int m,int n)
        {
            v1 = m;
            v2 = n;
         } 
         void PrintValue();
};

void BaseClass::PrintValue()
{
    cout<<"v1="<<v1<<"\tv2="<<v2;
}
class DerivedClass:public BaseClass
{
    int v3;
    public:
        void SetValue(int m,int n,int k)
        {
            v1 = m;
            v2 = n;
            v3 = k;
        }
        void SetValue(int m,int n)
        {
            v1 = m;
            v2 =n;
        }
        void PrintValue();
};

void DerivedClass::PrintValue()
{
    cout<<endl;
    BaseClass::PrintValue();
    cout<<"\tv3="<<v3<<endl;
}

int main()
{
    BaseClass baseCla;
    DerivedClass derivedCla;
    cout<<"初始時的隨機(jī)值:  "<<endl;
    baseCla.PrintValue();
    derivedCla.PrintValue();
    cout<<"修改基類中的值后:  "<<endl;
    baseCla.SetValue(10,20);
    baseCla.PrintValue();
    derivedCla.PrintValue();
    cout<<"從派生類修改從基類繼承的值及本類的值:  "<<endl;
    derivedCla.SetValue(100,200,300);
    baseCla.PrintValue();
    derivedCla.PrintValue();
    return 0; 
}

初始時的隨機(jī)值:
v1=0    v2=0
v1=0    v2=0    v3=19
修改基類中的值后:
v1=10   v2=20
v1=0    v2=0    v3=19
從派生類修改從基類繼承的值及本類的值:
v1=10   v2=20
v1=100  v2=200  v3=300

多重繼承

C++允許從多個類派生一個類,即一個派生類可以同時有多個基類金句。這稱為多重繼承檩赢。

從一個基類派生一個派生類的情況,稱為單繼承或單重繼承违寞。

一個類從多個基類派生的格式

class 派生類名 : 繼承方式說明符 基類名1贞瞒,繼承方式說明符 基類名2,...坞靶,繼承方式說明符 基類名n
{
  類體
};

程序5-10 多重繼承下的訪問方式

#include <iostream>
using namespace std;

class CB1
{
    public:
        int a;      //重名
        CB1(int x)
        {
            a = x;
         } 
        void showa()        //重名
        {
            cout<<"Class CB1==>a="<<a<<endl; 
        }
};

class CB2
{
    public:
        int a;      //重名
        CB2(int x)
        {
            a = x;
         } 
        void showa()        //重名
        {
            cout<<"Class CB2==>a="<<a<<endl; 
        }
};

class CD : public CB1,public CB2        //多重繼承憔狞,兩個基類 
{
    public:
        int a;      //與兩個基類成員變量a重名
        CD(int x,int y,int z):CB1(x),CB2(y)
        {
            a = z;
         } 
        void showa()        //與兩個基類成員函數(shù)showa()重名
        {
            cout<<"Class CD==>a="<<a<<endl; 
        }
        void print3a()
        {
            cout<<"a="<<a<<endl;
            cout<<"CB1::a="<<CB1::a<<endl;
            cout<<"CB2::a="<<CB2::a<<endl;
        }
};

int main()
{
    CB1 CB1obj(11);
    CB1obj.showa();
    CD CDobj(101,202,909);
    CDobj.showa();
    CDobj.CB1::showa();
    cout<<"CDobj.a="<<CDobj.a<<endl;
    cout<<"CDobj.CB2::a="<<CDobj.CB2::a<<endl;
}

Class CB1==>a=11
Class CD==>a=909
Class CB1==>a=101
CDobj.a=909
CDobj.CB2::a=202

多重繼承方式下,為避免二義性彰阴,成員變量的訪問方式如下
程序5-11 多重繼承

#include <iostream>
using namespace std;

class BaseClass1
{
    public:
        int v1,v2;
        BaseClass1();
        BaseClass1(int,int);
        ~BaseClass1(); 
};

BaseClass1::BaseClass1()
{
    cout<<"BaseClass1 無參構(gòu)造函數(shù)"<<endl;
}

BaseClass1::BaseClass1(int m,int n):v1(m),v2(n)
{
    cout<<"BaseClass1 帶2個參數(shù)構(gòu)造函數(shù)"<<endl;
}

BaseClass1::~BaseClass1()
{
    cout<<"BaseClass1 析構(gòu)函數(shù)"<<endl;
}

class BaseClass2
{
    public:
        int v1,v4;
        BaseClass2();
        BaseClass2(int,int);
        ~BaseClass2();
};

BaseClass2::BaseClass2()
{
    cout<<"BaseClass2 無參構(gòu)造函數(shù)"<<endl;
}

BaseClass2::BaseClass2(int m,int n):v1(m),v4(n)
{
    cout<<"BaseClass2 帶2個參數(shù)構(gòu)造函數(shù)"<<endl;
}

BaseClass2::~BaseClass2()
{
    cout<<"BaseClass2 析構(gòu)函數(shù)"<<endl;
}

class DerivedClass:public BaseClass1,public BaseClass2
{
    public:
        int v3;
    public:
        DerivedClass();
        DerivedClass(int);
        DerivedClass(int,int,int,int);
        ~DerivedClass();
};

DerivedClass::DerivedClass()
{
    cout<<"DerivedClass 無參構(gòu)造函數(shù)"<<endl;
}

DerivedClass::DerivedClass(int k):v3(k)
{
    cout<<"DerivedClass 帶1個參數(shù)的構(gòu)造函數(shù)"<<endl;
}

DerivedClass::DerivedClass(int m,int n,int k,int t):BaseClass1(m,n),BaseClass2(m,t),v3(k)
{
    cout<<"DerivedClass 帶4個參數(shù)的構(gòu)造函數(shù)"<<endl;
}

DerivedClass::~DerivedClass()
{
    cout<<"DerivedClass 析構(gòu)函數(shù)"<<endl;
}

int main()
{
    cout<<"帶參數(shù)對象的創(chuàng)建"<<endl;
    DerivedClass derivedCla1(1000,2000,3000,4000);
    cout<<"v1="<<derivedCla1.BaseClass1::v1<<endl;
    cout<<"v2="<<derivedCla1.v2<<endl;
    cout<<"v1="<<derivedCla1.BaseClass2::v1<<endl;
    cout<<"v4="<<derivedCla1.v4<<endl;
    cout<<"v3="<<derivedCla1.v3<<endl;
    return 0;
}

帶參數(shù)對象的創(chuàng)建
BaseClass1 帶2個參數(shù)構(gòu)造函數(shù)
BaseClass2 帶2個參數(shù)構(gòu)造函數(shù)
DerivedClass 帶4個參數(shù)的構(gòu)造函數(shù)
v1=1000
v2=2000
v1=1000
v4=4000
v3=3000
DerivedClass 析構(gòu)函數(shù)
BaseClass2 析構(gòu)函數(shù)
BaseClass1 析構(gòu)函數(shù)

二瘾敢、 訪問控制

公有繼承

當(dāng)類的繼承方式為公有繼承時,基類的公有成員在派生類中直接訪問尿这,在基類與派生類外直接訪問;基類的保護(hù)成員在派生類中直接訪問,在基類與派生類外調(diào)用公有函數(shù)訪問;基類的私有成員在派生類中調(diào)用公有函數(shù)訪問,在基類與派生類外調(diào)用公有函數(shù)訪問簇抵。

當(dāng)類的繼承方式為公有繼承時,派生類中定義的公有成員在派生類中直接訪問.在基類與派生類外直接訪問;派生類中定義的保護(hù)成員在派生類中直接訪問射众,在基類與派生類外調(diào)用公有函數(shù)訪問;派生類中定義的私有成員在派生類中直接訪問,在基類與派生類外調(diào)用公有函數(shù)訪問碟摆。
表5-1 公有繼承的訪問控制

各成員 派生類中 基類與派生類外
基類的公有成員 直接訪問 直接訪問
基類的保護(hù)成員 直接訪問 調(diào)用公有函數(shù)訪問
基類的私有成員 調(diào)用公有函數(shù)訪問 調(diào)用公有函數(shù)訪問
從基類繼承的公有成員 直接訪問 直接訪問
從基類繼承的保護(hù)成員 直接訪問 調(diào)用公有函數(shù)訪問
從基類繼承的私有成員 調(diào)用公有函數(shù)訪問 調(diào)用公有函數(shù)訪問
派生類中定義的公有成員 直接訪問 直接訪問
派生類中定義的保護(hù)成員 直接訪問 調(diào)用公有函數(shù)訪問
派生類中定義的私有成員 直接訪問 調(diào)用公有函數(shù)訪問

程序5-12 公有繼承訪問控制示例

#include <iostream>
#include <string>
using namespace std;

class Base
{
    public:
        int vBPub;
    protected:
        int vBPro;
    private:
        int vBPri;
    public:
        Base()
        {
            vBPub = 10;
            vBPro = 20;
            vBPri = 30;
        };
        void SetPriValue(int);
        void SetProValue(int,int);
        int GetPriValue();
        int GetProValue();
};

void Base::SetPriValue(int k)
{
    vBPri = k;
}

void Base::SetProValue(int m,int n)
{
    vBPro = m;
    vBPri = n;
}

int Base::GetPriValue()
{
    return vBPri;
}

int Base::GetProValue()
{
    return vBPro;
}

class Derived:public Base
{
    public:
        int vDPub,vBPub;
    protected:
        int vDPro;
    private:
        int vDPri;
    public:
        Derived()
        {
            vDPub = 100;
            vDPro = 200;
            vDPri = 300;
            vBPub = 15;
        };
        void SetPriValue(int);
        void SetProValue(int,int);
        int GetPriValue();
        int GetProValue();
        void PrintValue();
};

void Derived::SetPriValue(int k)
{
    vDPri = k;
}

void Derived::SetProValue(int m,int n)
{
    vDPro = m;
    vDPri = n;
    Base::vBPro = 2*m;
//  Base::vBPri = 2*n;      //不可以直接訪問從基類繼承的私有成員變量
     
}

int Derived::GetPriValue()
{
    return vDPri;
 } 
 
int Derived::GetProValue()
{
    return vDPro;
}

void Derived::PrintValue()
{
    cout<<"在派生類中訪問基類"<<endl;
    cout<<"基類公有變量: "<<vBPub<<endl;      //派生類可以訪問基類的公有成員變量
    cout<<"基類保護(hù)變量: "<<vBPro<<endl;      //派生類可以訪問基類的保護(hù)成員變量
//  cout<<Base::vBPri<<endl;                    //不能直接訪問基類的私有變量
    cout<<"基類私有變量: "<<Base::GetPriValue()<<endl;    //通過函數(shù)訪問
    cout<<"在派生類中訪問派生類"<<endl;
    cout<<"派生類公有變量: "<<vDPub<<endl;
    cout<<"派生類保護(hù)變量: "<<vDPro<<endl;
    cout<<"派生類私有變量: "<<vDPri<<endl;
    cout<<"從基類繼承的公有變量: "<<Base::vBPub<<endl;
    cout<<"從基類繼承的保護(hù)變量: "<<Base::vBPro<<endl;
//  cout<<"從基類繼承的私有變量: "<<Base::vBPri<<endl;    //不可以直接訪問 
}

int main()
{
    Base bObj;
    Derived dObj;
    cout<<"在主函數(shù)中訪問基類"<<endl;
    cout<<"公有成員: "<<bObj.vBPub<<endl;
//  cout<<"保護(hù)成員: "<<bObj.vBPro<<endl;       //不能直接訪問保護(hù)成員變量
    cout<<"保護(hù)成員: "<<bObj.GetProValue()<<endl;       //通過函數(shù)訪問
    cout<<"私有成員: "<<bObj.GetPriValue()<<endl;
    
    cout<<"在主函數(shù)中訪問派生類"<<endl;
    cout<<"公有成員: "<<dObj.vDPub<<endl;
//  cout<<"保護(hù)成員: "<<dObj.vDpro<<endl;       //不能直接訪問保護(hù)成員變量
    cout<<"保護(hù)成員: "<<dObj.GetProValue()<<endl;
    cout<<"基類  保護(hù)成員: "<<dObj.Base::GetProValue()<<endl;
    cout<<"私有成員: "<<dObj.GetPriValue()<<endl;
    cout<<"dObj.vBPub="<<dObj.vBPub<<endl;
    cout<<"dObj.Base::vBpub="<<dObj.Base::vBPub<<endl;
    dObj.PrintValue();
    
    return 0; 
 } 

在主函數(shù)中訪問基類
公有成員: 10
保護(hù)成員: 20
私有成員: 30
在主函數(shù)中訪問派生類
公有成員: 100
保護(hù)成員: 200
基類  保護(hù)成員: 20
私有成員: 300
dObj.vBPub=15
dObj.Base::vBpub=10
在派生類中訪問基類
基類公有變量: 15
基類保護(hù)變量: 20
基類私有變量: 30
在派生類中訪問派生類
派生類公有變量: 100
派生類保護(hù)變量: 200
派生類私有變量: 300
從基類繼承的公有變量: 10
從基類繼承的保護(hù)變量: 20

類型兼容規(guī)則

類型兼容規(guī)則是指在需要基類對象的任何地方,都可以使用公有派生類的對象來替代叨橱,也稱為賦值兼容規(guī)則典蜕。

在公有派生的情況下断盛,又以下3條類型兼容規(guī)則。

  • 派生類的對象可以賦值給基類對象愉舔。
  • 派生類對象可以用來初始化基類引用钢猛。
  • 派生類對象的地址可以賦值給基類指針。

程序5-13 類型兼容規(guī)則的使用

#include <iostream>
using namespace std;

class A
{
    int an;
    public:
        A(){}
        A(int n)
        {
            an = n;
        }
};

class B:public A
{
    int bn;
    public:
        B(int n):A(2*n)
        {
            bn = n;
        }
};

int main()
{
    A a(10);
    B b(20);
    a = b;
    
    return 0;
}

程序5-14 驗(yàn)證使用類型兼容規(guī)則的輸出結(jié)果

#include <iostream>
using namespace std;

class A
{
    int an;
    public:
        A(){}
        A(int n)
        {
            an = n;
        }
        void print()
        {
            cout<<"A的對象:";
            cout<<"an:"<<an;
        }
        void print(int k)
        {
            cout<<"an:"<<an;
        }
};

class B:public A
{
    int bn;
    public:
        B(int n):A(2*n)
        {
            bn = n;
        }
        void print()
        {
            cout<<"\nB的對象:";
            A::print(1);
            cout<<",bn="<<bn<<endl;
        }
};

int main()
{
    A a(10);
    B b(20);
    a.print();
    b.print();
    a = b;
    a.print();
    b.print();
    
    return 0;
}

A的對象:an:10
B的對象:an:40,bn=20
A的對象:an:40
B的對象:an:40,bn=20

私有繼承

當(dāng)類的繼承方式為私有繼承時,基類的公有成員在第一級派生類中可以直接訪問轩缤,在第二級派生類中不可訪問,在基類與派生類外不可訪問;基類的保護(hù)成員在第一級派生類中可以直接訪問,在第二級派生類中不可訪問,在基類與派生類外不可訪向;基類的私有成員在第一級派生類中可以調(diào)用公有函數(shù)訪問,在第二級派生類中不可訪問命迈,在基類與派生類外不可訪問。

表5-2 私有繼承的訪問控制

第一級派生類中 第二級派生類中 基類與派生類外
基類的公有成員 直接訪問 不可訪問 不可訪問
基類的保護(hù)成員 直接訪問 不可訪問 不可訪問
基類的私有成員 調(diào)用公有函數(shù)訪問 不可訪問 不可訪問

保護(hù)繼承

保護(hù)繼承中火的,基類的公有成員和保護(hù)成員都以保護(hù)成員的身份出現(xiàn)在派生類中,而基類的私有成員不可以直接訪問壶愤。這樣,派生類的其他成員可以直接訪問從基類繼承來的公有和保護(hù)成員,但在類外通過派生類的對象無法直接訪問他們馏鹤。

三征椒、派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)

構(gòu)造函數(shù)與析構(gòu)函數(shù)

在執(zhí)行一個派生類的構(gòu)造函數(shù)之前,總是先執(zhí)行基類的構(gòu)造函數(shù)假瞬。派生類對象消亡時陕靠,先執(zhí)行派生類的析構(gòu)函數(shù),在執(zhí)行基類的析構(gòu)函數(shù)脱茉。

如果基類定義了帶有形參表的構(gòu)造函數(shù)剪芥,則派生類就應(yīng)當(dāng)定義構(gòu)造函數(shù)。

定義派生類構(gòu)造函數(shù)的格式

派生類名::派生類名(參數(shù)表):基類名1(基類1 初始化參數(shù)表),...,基類名m(基類m初始化參數(shù)表),成員對象名1(成員對象1 初始化參數(shù)表),...,成員對象名n(成員對象n 初始化參數(shù)表)
{
  派生類構(gòu)造函數(shù)函數(shù)體   //其他初始化操作
}

程序5-15 基類和派生類的構(gòu)造函數(shù)與析構(gòu)函數(shù)

#include <iostream>
using namespace std;
class BaseClass
{
    protected:
        int v1,v2;
    public:
        BaseClass();
        BaseClass(int,int);
        ~BaseClass();
};

BaseClass::BaseClass()
{
    cout<<"BaseClass 無參構(gòu)造函數(shù)"<<endl;
}
BaseClass::BaseClass(int m,int n)
{
    v1 = m;
    v2 = n;
    cout<<"BaseClass 2個參數(shù)構(gòu)造函數(shù)"<<endl;
}

BaseClass::~BaseClass()
{
    cout<<"BaseClass 析構(gòu)函數(shù)"<<endl;
}

class DerivedClass:public BaseClass
{
    int v3;
    public:
        DerivedClass();
        DerivedClass(int);
        DerivedClass(int,int,int);
        ~DerivedClass();
};

DerivedClass::DerivedClass()
{
    cout<<"DerivedClass 無參構(gòu)造函數(shù)"<<endl;
}

DerivedClass::DerivedClass(int k):v3(k)
{
    cout<<"DerivedClass 帶1個參數(shù)的構(gòu)造函數(shù)"<<endl;
}

DerivedClass::DerivedClass(int m,int n,int k):BaseClass(m,n),v3(k)
{
    cout<<"DerivedClass 帶3個參數(shù)的構(gòu)造函數(shù)"<<endl;
}

DerivedClass::~DerivedClass()
{
    cout<<"DerivedClass 析構(gòu)函數(shù)"<<endl;
}

int main()
{
    cout<<"無參對象的創(chuàng)建"<<endl;
    BaseClass baseCla;
    DerivedClass derivedCla;
    return 0;
}

無參對象的創(chuàng)建
BaseClass 無參構(gòu)造函數(shù)
BaseClass 無參構(gòu)造函數(shù)
DerivedClass 無參構(gòu)造函數(shù)
DerivedClass 析構(gòu)函數(shù)
BaseClass 析構(gòu)函數(shù)
BaseClass 析構(gòu)函數(shù)

例5-11 修改程序5-15
將主函數(shù)修改如下:

int main()
{
    cout<<"帶參數(shù)對象的創(chuàng)建"<<endl;
    BaseClass baseCla1(10,20);
    DerivedClass derivedCla1(30);
    return 0;
}

帶參數(shù)對象的創(chuàng)建
BaseClass 2個參數(shù)構(gòu)造函數(shù)
BaseClass 無參構(gòu)造函數(shù)
DerivedClass 帶1個參數(shù)的構(gòu)造函數(shù)
DerivedClass 析構(gòu)函數(shù)
BaseClass 析構(gòu)函數(shù)
BaseClass 析構(gòu)函數(shù)

例5-12

int main()
{
    cout<<"無參對象的創(chuàng)建"<<endl;
    BaseClass baseCla;
    DerivedClass derivedCla;
    cout<<"帶參數(shù)對象的創(chuàng)建"<<endl;
    BaseClass baseCla1(10,20);
    DerivedClass derivedCla1(30);
    return 0;
}

無參對象的創(chuàng)建
BaseClass 無參構(gòu)造函數(shù)
BaseClass 無參構(gòu)造函數(shù)
DerivedClass 無參構(gòu)造函數(shù)
帶參數(shù)對象的創(chuàng)建
BaseClass 2個參數(shù)構(gòu)造函數(shù)
BaseClass 無參構(gòu)造函數(shù)
DerivedClass 帶1個參數(shù)的構(gòu)造函數(shù)
DerivedClass 析構(gòu)函數(shù)
BaseClass 析構(gòu)函數(shù)
BaseClass 析構(gòu)函數(shù)
DerivedClass 析構(gòu)函數(shù)
BaseClass 析構(gòu)函數(shù)
BaseClass 析構(gòu)函數(shù)

程序5-16 調(diào)用基類和派生類的構(gòu)造函數(shù)琴许、析構(gòu)函數(shù)和成員函數(shù)

#include <iostream>
using namespace std;

class Base
{
    private:
        int Y;
    public:
        Base(int y = 0)
        {
            Y = y;
            cout<<"Base("<<y<<")"<<endl;
        }
        ~Base()
        {
            cout<<"~Base()"<<endl;
        }
        void print()
        {
            cout<<Y<<" ";
        }
};

class Derived:public Base
{
    private:
        int Z;
    public:
        Derived(int y,int z):Base(y)
        {
            Z = z;
            cout<<"Derived("<<y<<","<<z<<")"<<endl;
        }
        ~Derived()
        {
            cout<<"~Derived()"<<endl;
        }
        void print()
        {
            Base::print();
            cout<<Z<<endl;
        }
};

int main()
{
    Derived d(10,20);
    d.print();
    return 0;
}

Base(10)
Derived(10,20)
10 20
~Derived()
~Base()

復(fù)制構(gòu)造函數(shù)

程序5-17 派生類中的復(fù)制構(gòu)造函數(shù)

#include <iostream>
using namespace std;

class A
{
    public:
        A()
        {
            i = 100;
            cout<<"類A默認(rèn)構(gòu)造函數(shù)"<<endl;
        }
        A(const A &s)
        {
            i = s.i;
            cout<<"類A復(fù)制構(gòu)造函數(shù)"<<endl;
        }
        int getValue();
        void setValue(int);
    private:
        int i;
};

int A::getValue()
{
    return i;
}

void A::setValue(int k)
{
    i = k;
}

class B:public A        //公有派生類 
{
    private:
        float f;
    public:
        B()
        {
            f = 20.1;
            cout<<"類B默認(rèn)構(gòu)造函數(shù)"<<endl;
        }
        B(const B &v):A::A(v),f(v.f)
        {
            cout<<"類B復(fù)制構(gòu)造函數(shù)"<<endl;
        }
        float getValue();
        int getValue1()
        {
            return A::getValue();
        }
};

float B::getValue()
{
    return f;
}

int main()
{
    A a;
    B b;
    B bb(b);
    return 0;
}

類A默認(rèn)構(gòu)造函數(shù)
類A默認(rèn)構(gòu)造函數(shù)
類B默認(rèn)構(gòu)造函數(shù)
類A復(fù)制構(gòu)造函數(shù)
類B復(fù)制構(gòu)造函數(shù)

程序5-18 賦值運(yùn)算符的重載及使用

#include <iostream>
using namespace std;

class CBase
{
    public:
        CBase(){}
        CBase(CBase & c)
        {
            cout<<"CBase::復(fù)制構(gòu)造函數(shù)"<<endl;
        }
        CBase & operator=(const CBase &b)
        {
            cout<<"CBase::operator="<<endl;
            return *this;
        }
};
class CDerived:public CBase
{
    public:
        CDerived()
        {
            cout<<"CDerived::復(fù)制構(gòu)造函數(shù)"<<endl;
         } 
};

int main()
{
    CDerived d1,d2;
    CDerived d3(d1);        //d3初始化過程中會調(diào)用類CBase的復(fù)制構(gòu)造函數(shù) 
    d2 = d1;                //會調(diào)用類CBase重載的“=”運(yùn)算符 
    return 0;
}

CDerived::復(fù)制構(gòu)造函數(shù)
CDerived::復(fù)制構(gòu)造函數(shù)
CBase::復(fù)制構(gòu)造函數(shù)
CBase::operator=

多重繼承的構(gòu)造函數(shù)與析構(gòu)函數(shù)

設(shè)計(jì)兩個基類BaseClass1和BaseClass2共同派生一個派生類DerivedClass税肪。

程序5-19 多重繼承

#include <iostream>
using namespace std;
class BaseClass1
{
    protected:
        int v1,v2;
    public:
        BaseClass1();
        BaseClass1(int,int);
        ~BaseClass1();
        void SetValue(int,int);
        void PrintValue();
};

BaseClass1::BaseClass1():v1(0),v2(0)
{
    cout<<"BaseClass1 無參構(gòu)造函數(shù)"<<endl;
}

BaseClass1::BaseClass1(int m,int n)
{
    v1 = m;
    v2 = n;
    cout<<"BaseClass1 帶2個參數(shù)構(gòu)造函數(shù)"<<endl;
}

BaseClass1::~BaseClass1()
{
    cout<<"BaseClass1 析構(gòu)函數(shù)"<<endl;
}

void BaseClass1::SetValue(int m,int n)
{
    v1 = m;
    v2 = n;
}

void BaseClass1::PrintValue()
{
    cout<<"v1="<<v1<<"\tv2="<<v2;
}


class BaseClass2
{
    protected:
        int v1,v4;
    public:
        BaseClass2();
        BaseClass2(int,int);
        ~BaseClass2();
        void SetValue(int,int);
        void PrintValue();
};

BaseClass2::BaseClass2():v1(1),v4(1)
{
    cout<<"BaseClass2 無參構(gòu)造函數(shù)"<<endl; 
}

BaseClass2::BaseClass2(int m,int n)
{
    v1 = m;
    v4 = n;
    cout<<"BaseClass2 帶2個參數(shù)構(gòu)造函數(shù)"<<endl;
}

BaseClass2::~BaseClass2()
{
    cout<<"BaseClass2 析構(gòu)函數(shù)"<<endl;
}

void BaseClass2::SetValue(int m,int n)
{
    v1 = m;
    v4 = n;
}

void BaseClass2::PrintValue()
{
    cout<<"v1="<<v1<<"\tv4="<<v4;
}

class DerivedClass :public BaseClass1,public BaseClass2
{
    public:
        int v3;
    public:
        DerivedClass();
        DerivedClass(int);
        DerivedClass(int,int,int,int);
        ~DerivedClass();
        void SetValue(int m,int n,int k,int h)
        {
            BaseClass1::SetValue(m,n);
            BaseClass2::SetValue(2*m,h);
            v3 = k; 
         }
        void SetValue(int m,int n,int k)
        {
            BaseClass1::SetValue(m,n);
            BaseClass2::SetValue(2*m,2*n);
            v3 = k;
        }
        
        void SetValue(int m,int n)
        {
            BaseClass1::SetValue(m,n);
            BaseClass2::SetValue(-1,-1);
            v3 = -1;
        }
        void PrintValue();
};

DerivedClass::DerivedClass():BaseClass1(0,0),BaseClass2(0,0),v3(0)
{
    cout<<"DerivedClass 無參構(gòu)造函數(shù)"<<endl;
}

DerivedClass::DerivedClass(int k)
{
    v3 = k;
    cout<<"DerivedClass 帶1個參數(shù)的構(gòu)造函數(shù)"<<endl; 
}

DerivedClass::DerivedClass(int m,int n,int k,int t):BaseClass1(m,n),BaseClass2(m,t),v3(k)
{
    cout<<"DerivedClass 帶4個參數(shù)的構(gòu)造函數(shù)"<<endl;
}

DerivedClass::~DerivedClass()
{
    cout<<"DerivedClass 析構(gòu)函數(shù)"<<endl;
}

void DerivedClass::PrintValue()
{
    BaseClass1::PrintValue();
    cout<<"\tv3="<<v3<<endl;
    BaseClass2::PrintValue();
    cout<<endl;
}

int main()
{
    cout<<"帶參數(shù)對象的創(chuàng)建"<<endl;
    DerivedClass derivedCla1(1000,2000,3000,4000);
    derivedCla1.PrintValue();
    return 0;
}

帶參數(shù)對象的創(chuàng)建
BaseClass1 帶2個參數(shù)構(gòu)造函數(shù)
BaseClass2 帶2個參數(shù)構(gòu)造函數(shù)
DerivedClass 帶4個參數(shù)的構(gòu)造函數(shù)
v1=1000 v2=2000 v3=3000
v1=1000 v4=4000
DerivedClass 析構(gòu)函數(shù)
BaseClass2 析構(gòu)函數(shù)
BaseClass1 析構(gòu)函數(shù)

四、類之間的關(guān)系

類與類之間的關(guān)系

使用已有類編寫新的類有兩種方式:繼承和組合榜田。

封閉類的派生

如果一個類的成員變量是另一個類的對象益兄,則為封閉類。
定義封閉類構(gòu)造函數(shù)的形式

類名::類名(形參表):內(nèi)嵌對象1(形參表),內(nèi)嵌對象2(形參表),...
{
  類體
}

程序5-20 封閉類的構(gòu)造函數(shù)

#include <iostream>
#include <string>
using namespace std;

class myDate
{
    public:
        myDate();       //構(gòu)造函數(shù)
        myDate(int);
        myDate(int,int);
        myDate(int,int,int);    //構(gòu)造函數(shù)
        myDate(const myDate &d);
        ~myDate();
        void setDate(int,int,int);  //設(shè)置日期
        void setDate(myDate);    //設(shè)置日期
        myDate getDate();   //獲取日期
        void setYear(int);  //設(shè)置年
        int getMonth();//獲取月
        void printDate() const;     //打印日期
    private:
        int year,month,day;     //成員變量箭券,表示年净捅、月、日 
 };
//在類體外定義成員函數(shù)
myDate::myDate()
{
    year = 1970;
    month = 1;
    day = 1;
    cout<<"myDate默認(rèn)構(gòu)造函數(shù)"<<endl;
}

myDate::myDate(int y)
{
    year = y;
    month = 1;
    day = 1;
    cout<<"myDate 帶1個參數(shù)的構(gòu)造函數(shù)"<<endl;
}

myDate::myDate(int y,int m)
{
    year = y;
    month = m;
    day = 1;
    cout<<"myDate 帶2個參數(shù)的構(gòu)造函數(shù)"<<endl;
}

myDate::myDate(int y,int m,int d)
{
    year = y;
    month = m;
    day = d;
    cout<<"myDate 帶3個參數(shù)的構(gòu)造函數(shù)"<<endl;
}

myDate::myDate(const myDate &d)
{
    year = d.year;
    month = d.month;
    day = d.day;
    cout<<"myDate_COPY 構(gòu)造函數(shù)"<<endl;
}

myDate::~myDate()
{
    cout<<"myDate 析構(gòu)函數(shù)"<<endl;
}

void myDate::setDate(int y,int m,int d)
{
    year=y;
    month=m;
    day=d;
    return;
}
void myDate::setDate(myDate oneD)
{
    year=oneD.year;
    month=oneD.month;
    day=oneD.day;
    return;
}
myDate myDate::getDate()
{
    myDate d;
    d.year = year;
    d.month = month;
    d.day = day;
    return d;
}
void myDate::setYear(int y)
{
    year = y;
    return; 
}
int myDate::getMonth()
{
    return month;
}
void myDate::printDate() const
{
    cout<<year<<"/"<<month<<"/"<<day;
    return;
}

class CStudent
{
    public:
        CStudent();
        CStudent(string,myDate);
        ~CStudent();
        void setStudent(string,myDate); //設(shè)置學(xué)生信息
        void setName(string);           //設(shè)置學(xué)生姓名
        string getName();               //獲取姓名
        void setBirthday(myDate);       //設(shè)置生日
        myDate getBirthday();           //獲取生日
        void printInfo() const;     //打印信息
    private:
        string name;        //姓名
        myDate birthday;        //生日 
};

CStudent::CStudent():name("Noname"),birthday(myDate())
{
    cout<<"CStudent 默認(rèn)構(gòu)造函數(shù)"<<endl;
}

CStudent::CStudent(string str,myDate d):name(str),birthday(d)
{
    cout<<"CStudent 有參構(gòu)造函數(shù)"<<endl;
}

CStudent::~CStudent()
{
    cout<<"CStudent 析構(gòu)函數(shù)"<<endl;
}

void CStudent::setStudent(string s,myDate d)
{
    name = s;
    birthday.setDate(d);
    return;
}

void CStudent::setName(string n)
{
    name = n;
    return;
}

string CStudent::getName()
{
    return name;
}

void CStudent::setBirthday(myDate d)
{
    birthday.setDate(d);
    return;
}

myDate CStudent::getBirthday()
{
    return birthday;
}

void CStudent::printInfo()const
{
    cout<<"姓名: "<<name<<"\t生日: ";
    birthday.printDate();       //調(diào)用類myDate的成員函數(shù)
    cout<<endl; 
}

class CUndergraduateStudent:public CStudent     //本科生類辩块,繼承于 CStudent
{
    private:
        string department;      //學(xué)生所屬的系名
    public:
        CUndergraduateStudent();
        CUndergraduateStudent(string,myDate);
        ~CUndergraduateStudent();
        void setDep(string);
        void PrintInfo();
};

CUndergraduateStudent::CUndergraduateStudent()
{
    cout<<"CUndergraduateStudent 默認(rèn)構(gòu)造函數(shù)"<<endl; 
}

CUndergraduateStudent::CUndergraduateStudent(string str,myDate d):CStudent(str,d)
{
    cout<<"CUndergraduateStudent 有參構(gòu)造函數(shù)"<<endl;
}

CUndergraduateStudent::~CUndergraduateStudent()
{
    cout<<"CUndergraduateStudent 析構(gòu)函數(shù)"<<endl;
}

void CUndergraduateStudent::setDep(string dep)
{
    department = dep;
}

void CUndergraduateStudent::PrintInfo()
{
    CStudent::printInfo();      //調(diào)用基類的printInfo函數(shù)
    cout<<"院系:\t"<<department<<endl<<endl; 
}

int main()
{
    CUndergraduateStudent s2("小張",myDate());
    return 0;
}

myDate默認(rèn)構(gòu)造函數(shù)
myDate_COPY 構(gòu)造函數(shù)
myDate_COPY 構(gòu)造函數(shù)
CStudent 有參構(gòu)造函數(shù)
myDate 析構(gòu)函數(shù)
CUndergraduateStudent 有參構(gòu)造函數(shù)
myDate 析構(gòu)函數(shù)
CUndergraduateStudent 析構(gòu)函數(shù)
CStudent 析構(gòu)函數(shù)
myDate 析構(gòu)函數(shù)

*互包含關(guān)系的類

在處理相對復(fù)雜的問題而需要考慮類的組合時蛔六,很可能遇到兩個類相互引用的情況,稱為循環(huán)依賴废亭。

class A      //類A的定義
{
  public:
    void f(B b);    //以類B對象為形參的成員函數(shù)
};
class B        //類B的定義
{
  public:
    void g(A a);    //以類A對象為形參的成員函數(shù)
}

解決辦法是使用前向引用聲明国章。

在提供一個完整的類定義之前,不能定義該類的對象豆村,也不能在內(nèi)聯(lián)成員函數(shù)中使用該類的對象液兽。

例5-15 互包含的類

#include <iostream>
#include <string>
using namespace std;
class B;        //前向引用聲明
class A
{
    int a;
    B b;            //不完整的類型定義 
};

class B
{
     A a;
     int b;
};

int main()
{
    return 0;
}

程序5-21 互包含的類

#include <iostream>
#include <string>
using namespace std;

class B;
class A
{
    public:
        int aInt;
        B *bPoint = NULL;
        void SetValue(int v)
        {
            aInt = v;
        }
};

class B
{
    public:
        A aCla;
        int bInt;
        void SetValue(int v)
        {
            bInt = v;
        }
};

int main()
{
    A ca;
    B cb;
    ca.bPoint = &cb;
    cout<<"ca.bPoint="<<ca.bPoint<<endl;
    cout<<"cb Addr="<<&cb<<endl;
    cout<<"ca.aInt="<<ca.aInt<<endl;
    cout<<"cb.aCLa.aInt="<<cb.aCla.aInt<<endl;
    cout<<"cb.bInt="<<cb.bInt<<endl;
    cout<<"分界線"<<endl;
    
    ca.SetValue(10);
    cb.SetValue(20);
    cb.aCla = ca;
    cout<<"ca.bPoint="<<ca.bPoint<<endl;
    cout<<"ca.aInt="<<ca.aInt<<endl;
    cout<<"cb.aCla.aInt="<<cb.aCla.aInt<<endl;
    cout<<"cb.bInt="<<cb.bInt<<endl;
    return 0; 
}

ca.bPoint=0x6ffde0
cb Addr=0x6ffde0
ca.aInt=0
cb.aCLa.aInt=-1
cb.bInt=1
分界線
ca.bPoint=0x6ffde0
ca.aInt=10
cb.aCla.aInt=10
cb.bInt=20

五、多層次的派生

在C++中掌动,派生可以是多層次的四啰。

在C++中宁玫,類之間的繼承關(guān)系具有傳遞性。

在定義派生類時拟逮,只需寫直接基類撬统,不需要寫間接基類。

程序5-22 多級派生時構(gòu)造函數(shù)的調(diào)用

#include <iostream>
using namespace std;
class BaseClass1
{
    protected:
        int v1,v2;
    public:
        BaseClass1();
        BaseClass1(int,int);
        ~BaseClass1();
};

BaseClass1::BaseClass1()
{
    cout<<"BaseClass1 無參構(gòu)造函數(shù)"<<endl;
}

BaseClass1::BaseClass1(int m,int n):v1(m),v2(n)
{
    cout<<"BaseClass1 帶2個參數(shù)構(gòu)造函數(shù)"<<endl;
}

BaseClass1::~BaseClass1()
{
    cout<<"BaseClass1 析構(gòu)函數(shù)"<<endl;
}

class BaseClass2:public BaseClass1
{
    protected:
        int v3;
    public:
        BaseClass2();
        BaseClass2(int);
        BaseClass2(int,int,int);
        ~BaseClass2();
};

BaseClass2::BaseClass2()
{
    cout<<"BaseClass2 無參構(gòu)造函數(shù)"<<endl;
}

BaseClass2::BaseClass2(int m):v3(m)
{
    cout<<"BaseClass2 帶1個參數(shù)構(gòu)造函數(shù)"<<endl;
}

BaseClass2::BaseClass2(int m,int n,int k):BaseClass1(m,n),v3(k)
{
    cout<<"BaseClass2 帶3個參數(shù)構(gòu)造函數(shù)"<<endl;
}

BaseClass2::~BaseClass2()
{
    cout<<"BaseClass2 析構(gòu)函數(shù)"<<endl;
}

class DerivedClass:public BaseClass2
{
    public:
        int v4;
    public:
        DerivedClass();
        DerivedClass(int);
        DerivedClass(int,int,int,int);
        ~DerivedClass();
};

DerivedClass::DerivedClass()
{
    cout<<"DerivedClass 無參構(gòu)造函數(shù)"<<endl;
}

DerivedClass::DerivedClass(int k):v4(k)
{
    cout<<"DerivedClass 帶1個參數(shù)構(gòu)造函數(shù)"<<endl;
}

DerivedClass::DerivedClass(int m,int n,int k,int t):BaseClass2(m,n,k),v4(t)
{
    cout<<"DerivedClass 帶4個參數(shù)構(gòu)造函數(shù)"<<endl;
}

DerivedClass::~DerivedClass()
{
    cout<<"DerivedClass 析構(gòu)函數(shù)"<<endl;
}

int main()
{
    cout<<"無參對象的創(chuàng)建"<<endl;
    DerivedClass derivedCla;
    return 0;
}

無參對象的創(chuàng)建
BaseClass1 無參構(gòu)造函數(shù)
BaseClass2 無參構(gòu)造函數(shù)
DerivedClass 無參構(gòu)造函數(shù)
DerivedClass 析構(gòu)函數(shù)
BaseClass2 析構(gòu)函數(shù)
BaseClass1 析構(gòu)函數(shù)

將程序5-22的主函數(shù)修改如下

int main()
{
    cout<<"帶參數(shù)對象的創(chuàng)建"<<endl;
    DerivedClass derivedCla1(1000,2000,3000,4000);
    return 0;
}

帶參數(shù)對象的創(chuàng)建
BaseClass1 帶2個參數(shù)構(gòu)造函數(shù)
BaseClass2 帶3個參數(shù)構(gòu)造函數(shù)
DerivedClass 帶4個參數(shù)構(gòu)造函數(shù)
DerivedClass 析構(gòu)函數(shù)
BaseClass2 析構(gòu)函數(shù)
BaseClass1 析構(gòu)函數(shù)

六敦迄、基類與派生類指針的互相轉(zhuǎn)換

對于指針類型,可以使用基類指針指向派生類對象凭迹,也可以將派生類的指針直接賦值給基類指針罚屋。
但即使基類指針指向的是一個派生類的對象,也不能通過基類指針訪問基類中沒有而僅在派生類中定義的成員函數(shù)嗅绸。
當(dāng)派生類指針指向基類對象時脾猛,必須要將基類對象進(jìn)行強(qiáng)制類型轉(zhuǎn)換,才能賦給派生類指針鱼鸠。

程序5-23 使用指針的情況

#include <iostream>
using namespace std;

class CBase
{
    protected:
        int n;
    public:
        CBase(int i):n(i){}
        void Print()
        {
            cout<<"CBase:n="<<n<<endl;
        }
};

class CDerived:public CBase
{
    public:
        int v;
        CDerived(int i):CBase(i),v(2*i){}
        void Func(){};
        void Print()
        {
            cout<<"CDerived:n="<<n<<endl;
            cout<<"CDerived:v="<<v<<endl;
        }
};

int main()
{
    CDerived objDerived(3);
    CBase objBase(5);
    CBase *pBase = &objDerived; //使用基類指針指向派生類對象
    
    CDerived *pDerived;
    pDerived = &objDerived;
    cout<<"使用派生類指針調(diào)用函數(shù)"<<endl;
    pDerived->Print();      //調(diào)用的時派生類中的函數(shù)
    pBase = pDerived;       //基類指針 = 派生類指針猛拴,正確
    cout<<"使用基類指針調(diào)用函數(shù)"<<endl;
    pBase->Print();     //調(diào)用的是基類中的函數(shù)
    //pBase->Func();    //錯誤,通過基類指針不能調(diào)用派生類函數(shù)
    //pDerived = pBase  //派生類指針 = 基類指針
    pDerived = (CDerived *)pBase;   //強(qiáng)制類型轉(zhuǎn)換蚀狰,派生類指針 = 基類指針
    cout<<"使用派生類指針調(diào)用函數(shù)"<<endl;
    pDerived->Print();  //調(diào)用的是派生類的函數(shù)
    return 0; 
}

使用派生類指針調(diào)用函數(shù)
CDerived:n=3
CDerived:v=6
使用基類指針調(diào)用函數(shù)
CBase:n=3
使用派生類指針調(diào)用函數(shù)
CDerived:n=3
CDerived:v=6
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末愉昆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子麻蹋,更是在濱河造成了極大的恐慌跛溉,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扮授,死亡現(xiàn)場離奇詭異芳室,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)刹勃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門堪侯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人荔仁,你說我怎么就攤上這事伍宦。” “怎么了咕晋?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵雹拄,是天一觀的道長。 經(jīng)常有香客問我掌呜,道長辈双,這世上最難降的妖魔是什么克饶? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮唉地,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘箱蟆。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布念祭。 她就那樣靜靜地躺著,像睡著了一般碍侦。 火紅的嫁衣襯著肌膚如雪粱坤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天瓷产,我揣著相機(jī)與錄音站玄,去河邊找鬼。 笑死濒旦,一個胖子當(dāng)著我的面吹牛株旷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播尔邓,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼晾剖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了梯嗽?” 一聲冷哼從身側(cè)響起齿尽,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎慷荔,沒想到半個月后雕什,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡显晶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年贷岸,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片磷雇。...
    茶點(diǎn)故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡偿警,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出唯笙,到底是詐尸還是另有隱情螟蒸,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布崩掘,位于F島的核電站七嫌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏苞慢。R本人自食惡果不足惜诵原,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绍赛,春花似錦蔓纠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蚯妇,卻和暖如春敷燎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背箩言。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工懈叹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人分扎。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像胧洒,于是被迫代替她去往敵國和親畏吓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 類的繼承與派生 繼承的概念 使用基類派生新類時卫漫,除構(gòu)造函數(shù)和析構(gòu)函數(shù)外 菲饼,基類的所有成員自動成為派生類的成員,包括...
    陳_MY閱讀 506評論 0 0
  • 類的繼承與類的派生 繼承和派生是人們認(rèn)識客觀世界的過程。在程序設(shè)計(jì)方法中包吝,人們追求代碼復(fù)用(這是提高軟件開發(fā)效率的...
    silasjs閱讀 1,260評論 0 1
  • 注意:本文中代碼均使用 Qt 開發(fā)編譯環(huán)境類的繼承與派生饼煞?以原有的類為基礎(chǔ)產(chǎn)生新的類,我們就說新類繼承了原有類的特...
    趙者也閱讀 1,477評論 0 1
  • 轉(zhuǎn)自大神博客凡程子 一诗越、基本概念 類的繼承砖瞧,是新的類從已有類那里得到已有的特性∪履或從已有類產(chǎn)生新類的過程就是類的派...
    leon4ever閱讀 482評論 0 0
  • 類的繼承與派生 類的繼承就是新類由已經(jīng)存在的類獲得已有特性块促,類的派生是由已經(jīng)存在的類產(chǎn)生新類的過程。已有類叫做基類...
    Mr希靈閱讀 613評論 0 1