寒假C++学习5-继承与派生

寒假C++学习5-继承与派生

1.概述

继承是从已有类那里得到已有的特性,已有的类称为基类或者父类,新类被称为派生类或者子类。

继承与派生是从不同角度说明类之间的关系,这种关系包含了访问机制,多态和重载等

2.继承(inheritance)

继承的实质就是用已有的数据类型创建新到的数据类型,并保留已有数据类型的特点,以旧类为基础创建新类,新类包含旧类的数据成员和成员函数

1)类的继承

1.继承形式
class 派生类名标识符 : [继承方式] 基类名标识符
{
    [访问控制修饰符:]
    [成员声明列表]
};

继承方式3种:public,protected,private

“:”是一个运算符,表示基类和派生类之间的继承关系,类似java的extends

举个例子:操作员继承员工的所有信息,此外还有密码和登录方法

class CEmployee
{
public:
    int ID;
    char Name[25];
};
 
class COperator : public CEmployee
{
public:
    char Password[128];
    bool login();
};

举个例子,操作员登录验证:

#include <bits/stdc++.h>
using namespace std;
class CEmployee                            //定义员工类
{
public:
    int m_ID;                                //定义员工ID
    char m_Name[128];                        //定义员工姓名
    char m_Depart[128];                        //定义所属部门
    CEmployee()                            //定义默认构造函数
    {
        memset(m_Name,0,128);                //初始化m_Name
        memset(m_Depart,0,128);            //初始化m_Depart
    }
    void OutputName()                            //定义共有成员函数
    {
        cout <<"员工姓名"<<m_Name<<endl;        //输出员工姓名
    }
};
class COperator :public CEmployee                //定义一个操作员类,从CEmployee类派生而来
{
public:
    char m_Password[128];                    //定义密码
    bool Login()                            //定义登录成员函数
    {
        if (strcmp(m_Name,"MR")==0 &&        //比较用户名
                strcmp(m_Password,"KJ")==0)        //比较密码
        {
            cout<<"登录成功!"<<endl;            //输出信息
            return true;                    //设置返回值
        }
        else
        {
            cout<<"登录失败!"<<endl;            //输出信息
            return false;                    //设置返回值
        }
    }
};
int main(int argc, char* argv[])
{
    COperator optr;                            //定义一个COperator类对象
    strcpy(optr.m_Name,"MR");                //访问基类的m_Name成员
    strcpy(optr.m_Password,"KJ");                //访问m_Password成员
    optr.Login();                            //调用COperator类的Login成员函数
    optr.OutputName();                        //调用基类CEmployee的OutputName成员函数
    return 0;
}

子类COperator继承父类CEmployee的所有非私有成员(private不能被继承)

注意:用户在父类中派生子类时,可能存在一种情况,即在子类中定义了一个与父类同名的成员函数,此时称为子类隐藏了父类的成员函数

2)继承后可访问性

1.公有型派生

共有型派生表示对于基类中的public数据成员和成员函数,在派生类中仍然是public,但是protected和private类依然是此类

举个例子:编译器会报错说pro是保护类,注意:基类的私有类在子类是不可见的,但是创建的时候是有空间,只是不可见

#include<bits/stdc++.h>
using namespace std;
 
class CEmployee
{
public:
    int ID;
    char Name[25];
protected:
    int pro;
    CEmployee(){
        pro = 6;
        ID = 1;
    }
};
 
class COperator : public CEmployee
{
public:
    char Password[128];
    bool login(){
        cout << "login!" << endl;
    }
};
 
 
int main(){
    COperator test;
    cout << test.pro << endl;
 
 
 
    return 0;
}
 
//error: 'int CEmployee::pro' is protected
2.保护型派生:
3.私有型派生

3)构造函数的访问顺序

注意:基类的构造函数和析构函数是不能被继承的;

由于父类和子类中都有构造函数和析构函数,那么在子类对象创建或者释放的时候会有个先后的顺序,这个顺序是:

当子类对象创建的时候,先调用父类的构造函数,然后访问子类的构造函数,释放的时候先调用子类的析构函数,在调用父类的析构函数

#include <bits/stdc++.h>
using namespace std;
class CEmployee                                //定义CEmployee类
{
public:
    int m_ID;                                    //定义数据成员
    char m_Name[128];                            //定义数据成员
    char m_Depart[128];                            //定义数据成员
    CEmployee()                                //定义构造函数
    {
        cout << "CEmployee类构造函数被调用"<< endl;        //输出信息
    }
    ~CEmployee()                                //析构函数
    {
        cout << "CEmployee类析构函数被调用"<< endl;        //输出信息
    }
};
class COperator :public CEmployee                    //从CEmployee类派生一个子类
{
public:
    char m_Password[128];                        //定义数据成员
    COperator()                                //定义构造函数
    {
        strcpy(m_Name,"MR");                    //设置数据成员
        cout << "COperator类构造函数被调用"<< endl;        //输出信息
    }
    ~COperator()                                //析构函数
    {
        cout << "COperator类析构函数被调用"<< endl;        //输出信息
    }
};
int main(int argc, char* argv[])                        //主函数
{
    COperator optr;                                //定义一个COperator对象
    return 0;
}
//CEmployee类构造函数被调用
//COperator类构造函数被调用
//COperator类析构函数被调用
//CEmployee类析构函数被调用

4)派生类构造函数的一般声明语法:

举个例子: C++中那个子类构造函数后面的”:”很类似java的super(),调用父类的构造函数

#include<bits/stdc++.h>
using namespace std;
 
class CEmployee
{
public:
    int ID;
    char Name[25];
protected:
    int pro;
    CEmployee(int ID,char* Name){
        pro = 6;
        this->ID = ID;
        strcpy(this->Name,Name);
    }
};
 
class COperator : public CEmployee
{
public:
    COperator(int m_ID,char* m_Name,char *m_Password) : CEmployee(m_ID,m_Name),Q()
    {
        strcpy(Password,m_Password);
    }
    char Password[128];
    bool login(){
        cout << "login!" << endl;
        cout << "ID:" << ID << endl;
        cout << "Name:" << Name << endl;
        cout << "Password:" << Password << endl;
        cout << "Q(age):" << Q.age << endl;
        return 1;
    }
    class nq
    {
    public:
        int age;
        nq(){
            age = 100;
        }
    };
    nq Q;
};
 
 
int main(){
    COperator test(6,"lalala","123");
    test.login();
 
    return 0;
}
//login!
//ID:6
//Name:lalala
//Password:123
//Q(age):100

5)子类显式调用父类构造函数

子类会自动的调用父类的默认构造函数,但是如果想使用父类带参数的构造函数,则需要使用显式的方式,同样的,当父类只有带参数的构造方法时,子类必须以显示方法调用父类带参数的构造函数,否则会报错

#include <bits/stdc++.h>
using namespace std;
class CEmployee                                        //定义CEmployee类
{
public:
    int m_ID;                                            //定义数据成员
    char m_Name[128];                                    //定义数据成员
    char m_Depart[128];                                    //定义数据成员
    CEmployee(char name[])                                //带参数的构造函数
    {
        strcpy(m_Name,name);
        cout << m_Name<<"调用了CEmployee类带参数的构造函数"<< endl;
    }
    CEmployee()                                        //无参构造函数
    {
        strcpy(m_Name,"MR");
        cout << m_Name<<"CEmployee类无参构造函数被调用"<< endl;
    }
    ~CEmployee()                                        //析构函数
    {
        cout << "CEmployee类析构函数被调用"<< endl;        //输出信息
    }
};
class COperator :public CEmployee                            //从CEmployee类派生一个子类
{
public:
    char m_Password[128];                                //定义数据成员
    COperator(char name[ ]):CEmployee(name)                //显示调用父类带参数的构造函数
    {        //设置数据成员
        cout << "COperator类构造函数被调用"<< endl;            //输出信息
    }
    COperator():CEmployee("JACK")                        //显示调用父类带参数的构造函数
    {        //设置数据成员
        cout << "COperator类构造函数被调用"<< endl;            //输出信息
    }
    ~COperator()                                        //析构函数
    {
        cout << "COperator类析构函数被调用"<< endl;            //输出信息
    }
};
int main(int argc, char* argv[])                                //主函数
{
    COperator optr1;                        //定义一个COperator对象,调用自身无参构造函数
    COperator optr2("LaoZhang");           //定义一个COperator对象,调用自身带参数构造函数
    return 0;
}

6)子类隐藏父类的成员函数

如果子类定义了一个和父类一样的成员函数,那么一个子类对象是调用子类的成员函数的

#include <bits/stdc++.h>
using namespace std;
class CEmployee    //定义CEmployee类
{
public:
    int m_ID;//定义数据成员
    char m_Name[128];//定义数据成员
    char m_Depart[128];
 
    CEmployee()//定义构造函数
    {
    }
    ~CEmployee()//析构函数
    {
    }
    void OutputName()//定义OutputName成员函数
    {
        cout << "调用CEmployee类的OutputName成员函数: "<< endl;    //输出操作员姓名
    }//定义数据成员
};
class COperator :public CEmployee//定义COperator类
{
public:
    char m_Password[128];//定义数据成员
    void OutputName()//定义OutputName成员函数
    {
        cout << "调用COperator类的OutputName成员函数:"<< endl;//输出操作员姓名
    }
 
};
int main(int argc, char* argv[])//主成员函数
{
    COperator optr;    //定义COperator对象
    optr.OutputName();//调用COperator类的OutputName成员函数
    return 0;
}

如果想要调用父类的构造函数,必须使用显示的构造函数

#include<bits/stdc++.h>
using namespace std;
 
class CEmployee
{
public:
    int a;
    double b;
    CEmployee()
    {
        a = 6;
    }
    CEmployee(int m_a)
    {
        a = m_a;
    }
};
 
class COperator : public CEmployee
{
public:
    int c;
    COperator():CEmployee()
    {
        c = 1;
    }
};
 
 
 
int main(){
    COperator test;
    cout << test.a << endl;
 
 
    return 0;
}
 
//6

3.重载运算符

1)重载运算符的必要性

运算符相当于一个函数,编译器对运算符的选择,遵循的是函数重载的原则

问题:如何实现两个类的相加?

#include<bits/stdc++.h>
using namespace std;
 
class node
{
public:
    int a;
    double c;
    node(){
        a = 1;
        c = 2;
    }
};
 
int main(){
    node test1,test2;
    test1.a = 6,test2.a =  1;
    cout << test1.a + test2.a << endl;    //7
    cout << test1 + test2 << endl;        //error!!!
 
 
    return 0;
}
 
//7
//error!

2)重载运算符的形式和规则

1.声明形式:
operator 类型名 ();

注意:C++重载运算符不可以是新创建的运算符,只能是C++语言中已经有的运算符:

1.算术运算符。2.位操作运算符。3.逻辑运算符。4.比较运算符。5.赋值运算符。6.其他运算符。

举个栗子:通过重载运算符求和

#include <bits/stdc++.h>
using namespace std;
class CBook
{
public:
    CBook (int iPage)
    {
        m_iPage=iPage;
    }
    CBook operator+( CBook b)
    {
        return CBook (m_iPage+b.m_iPage);
    }
    void display()
    {
        cout << m_iPage << endl;
    }
protected:
    int m_iPage;
};
 
int main()
{
    CBook bk1(10);
    CBook bk2(20);
    CBook tmp(0);
    tmp= bk1+bk2;
    tmp.display();
 
 
    return 0;
}
//30

3)重载运算符的运算

1.实现类与整数的相加

很简单,粘个代码

class CBook
{
public:
    int m_page;
    CBook()
    {
        m_page = 0;
    }
    CBook operator+(const int page)
    {
        CBook bk;
        bk.m_page = m_page + page;
        return bk;
    }
};

2.前置运算与后置运算的区别

对于++与–的前置与后置,C++默认是:如果重载运算符没有参数,那么表示前置运算,如果有参数,那就表示后置运算

void operator++()
{
    ++m_page;
}
 
void operator++(int)
{
    m_page++;
}

4)转换运算符

在C++中有强制转换类型,这样运算符就是转换运算符,例如

int i = 1;
double d = (double)i;//或者double(i)

此时double()在C++中被称为转换运算符,通过重载转换运算符可以实现将类对象转换成想要得到的数据,举个例子:

#include<bits/stdc++.h>
using namespace std;
 
class CBook
{
public:
    CBook(double ipage = 0);
    operator double()
    {
        return m_page;
    }
protected:
    int m_page;
};
 
CBook::CBook(double ipage)
{
    m_page = ipage;
}
 
int main(){
    CBook bk1(10.0);
    CBook bk2(20.00);
    cout << bk1 + bk2 << "  " << double(bk1) + double(bk2) << endl;
 
 
    return 0;
}
//30  30

4.多重继承

1)声明形式:

用逗号隔开,并且每个基类都要有继承方式(默认还是私有继承)

2)构造函数

顺序和单一继承一样:先基类然后内嵌对象最后派生类

析构也是一样,反过来

多重继承中基类的构造函数执行的顺序:按照声明中的先后顺序执行,不是构造函数中的顺序

举个例子:

#include<bits/stdc++.h>
using namespace std;
 
class Date
{
public:
    Date(){
        cout << "Date()" << endl;
    }
    ~Date(){
        cout << "~Data()" << endl;
    }
};
 
class Framer
{
public:
    Framer(){
        cout << "Framer()" << endl;
    }
    ~Framer(){
        cout << "~Framer()" << endl;
    }
    void sow(){
        cout << "sow" << endl;
    }
};
 
class Worker
{
public:
    Worker(){
        cout << "Worker()" << endl;
    }
    ~Worker(){
        cout << "~Worker()" << endl;
    }
    void work(){
        cout << "work!" << endl;
    }
};
 
class FramerWorker : public Framer,public Worker
{
public:
    FramerWorker(){
        cout << "FramerWorker()" << endl;
    }
    ~FramerWorker(){
        cout << "~FramerWorker()" << endl;
    }
};
 
int main(){
    FramerWorker test;
    test.sow();
    test.work();
 
 
    return 0;
}
 
//Framer()
//Worker()
//FramerWorker()
//sow
//work!
//~FramerWorker()
//~Worker()
//~Framer()

armer好像写成了Framer,qwq,忽略了~

3)二义性

1.产生

当一个派生类,在其作用域中没有某一个成员函数时,比如eat()函数,这时候它要从它的基类中寻找,如果多重继承的几个基类都有同名成员时(函数)会发生二义性,还有就是,如果派生类的几个基类也是某个基类的派生类,那么就可能会发生二义性,例如都从基类中派生类同样的函数,这样最后的派生类在调用成员函数的时候会发生二义性

举个例子:

#include<bits/stdc++.h>
using namespace std;
 
class Date
{
public:
    Date(){
        cout << "Date()" << endl;
    }
    ~Date(){
        cout << "~Data()" << endl;
    }
};
 
class Framer
{
public:
    Framer(){
        cout << "Framer()" << endl;
    }
    ~Framer(){
        cout << "~Framer()" << endl;
    }
    void sow(){
        cout << "sow" << endl;
    }
    void eat(){
        cout << "eat-Farmer" << endl;
    }
};
 
class Worker
{
public:
    Worker(){
        cout << "Worker()" << endl;
    }
    ~Worker(){
        cout << "~Worker()" << endl;
    }
    void work(){
        cout << "work!" << endl;
    }
    void eat(){
        cout << "eat-work" << endl;
    }
};
 
class FramerWorker : public Framer,public Worker
{
public:
    FramerWorker(){
        cout << "FramerWorker()" << endl;
    }
    ~FramerWorker(){
        cout << "~FramerWorker()" << endl;
    }
};
 
int main(){
    FramerWorker test;
    test.eat();
 
    return 0;
}

2.解决方法:

1)作用域标识符:

#include<bits/stdc++.h>
using namespace std;
 
class Date
{
public:
    Date(){
        cout << "Date()" << endl;
    }
    ~Date(){
        cout << "~Data()" << endl;
    }
};
 
class Framer
{
public:
    Framer(){
        cout << "Framer()" << endl;
    }
    ~Framer(){
        cout << "~Framer()" << endl;
    }
    void sow(){
        cout << "sow" << endl;
    }
    void eat(){
        cout << "eat-Farmer" << endl;
    }
};
 
class Worker
{
public:
    Worker(){
        cout << "Worker()" << endl;
    }
    ~Worker(){
        cout << "~Worker()" << endl;
    }
    void work(){
        cout << "work!" << endl;
    }
    void eat(){
        cout << "eat-work" << endl;
    }
};
 
class FramerWorker : public Framer,public Worker
{
public:
    FramerWorker(){
        cout << "FramerWorker()" << endl;
    }
    ~FramerWorker(){
        cout << "~FramerWorker()" << endl;
    }
};
 
int main(){
    FramerWorker test;
    test.Framer::eat();
 
    return 0;
}
 
//Framer()
//Worker()
//FramerWorker()
//eat-Farmer
//~FramerWorker()
//~Worker()
//~Framer()

2)在派生类中定义与基类相同的成员

#include<bits/stdc++.h>
using namespace std;
 
class Date
{
public:
    Date(){
        cout << "Date()" << endl;
    }
    ~Date(){
        cout << "~Data()" << endl;
    }
};
 
class Framer
{
public:
    Framer(){
        cout << "Framer()" << endl;
    }
    ~Framer(){
        cout << "~Framer()" << endl;
    }
    void sow(){
        cout << "sow" << endl;
    }
    void eat(){
        cout << "eat-Farmer" << endl;
    }
};
 
class Worker
{
public:
    Worker(){
        cout << "Worker()" << endl;
    }
    ~Worker(){
        cout << "~Worker()" << endl;
    }
    void work(){
        cout << "work!" << endl;
    }
    void eat(){
        cout << "eat-work" << endl;
    }
};
 
class FramerWorker : public Framer,public Worker
{
public:
    FramerWorker(){
        cout << "FramerWorker()" << endl;
    }
    ~FramerWorker(){
        cout << "~FramerWorker()" << endl;
    }
    void eat(){
        cout << "eat-FarmerWorker" << endl;
    }
    /* 或者这样:
     * void eat(){
           Worker::eat(); 
       }
    */
};
 
int main(){
    FramerWorker test;
    test.eat();
 
    return 0;
}
 
//Framer()
//Worker()
//FramerWorker()
//eat-FarmerWorker
//~FramerWorker()
//~Worker()
//~Framer()

3)注意:这样写是有问题的

#include<bits/stdc++.h>
using namespace std;
 
class Human
{
public:
    Human(){
        cout << "Human()" << endl;
    }
    ~Human(){
        cout << "~Human()" << endl;
    }
    void eat(){
        cout << "eat-Human" << endl;
    }
};
 
class Framer : public Human
{
public:
    Framer(){
        cout << "Framer()" << endl;
    }
    ~Framer(){
        cout << "~Framer()" << endl;
    }
    void sow(){
        cout << "sow" << endl;
    }
};
 
class Worker : public Human
{
public:
    Worker(){
        cout << "Worker()" << endl;
    }
    ~Worker(){
        cout << "~Worker()" << endl;
    }
    void work(){
        cout << "work!" << endl;
    }
};
 
class FramerWorker : public Framer,public Worker
{
public:
    FramerWorker(){
        cout << "FramerWorker()" << endl;
    }
    ~FramerWorker(){
        cout << "~FramerWorker()" << endl;
    }
};
 
int main(){
    FramerWorker test;
    test.Human::eat();
 
    return 0;
}

目前不是很理解为什么是错的,好像是:编译器不能理解是从Worker还是Farmer继承的qwq

#include<bits/stdc++.h>
using namespace std;
 
class Human
{
public:
    Human(){
        cout << "Human()" << endl;
    }
    ~Human(){
        cout << "~Human()" << endl;
    }
    void eat(){
        cout << "eat-Human" << endl;
    }
};
 
class Framer : public Human
{
public:
    Framer(){
        cout << "Framer()" << endl;
    }
    ~Framer(){
        cout << "~Framer()" << endl;
    }
    void sow(){
        cout << "sow" << endl;
    }
};
 
class Worker : public Human
{
public:
    Worker(){
        cout << "Worker()" << endl;
    }
    ~Worker(){
        cout << "~Worker()" << endl;
    }
    void work(){
        cout << "work!" << endl;
    }
};
 
class FramerWorker : public Framer,public Worker
{
public:
    FramerWorker(){
        cout << "FramerWorker()" << endl;
    }
    ~FramerWorker(){
        cout << "~FramerWorker()" << endl;
    }
};
 
int main(){
    FramerWorker test;
    //test.Human::eat();
    test.Framer::eat();
    test.Worker::eat();
 
 
    return 0;
}
 
//Human()
//Framer()
//Human()
//Worker()
//FramerWorker()
//eat-Human
//eat-Human
//~FramerWorker()
//~Worker()
//~Human()
//~Framer()
//~Human()

注意:这里发现Human被构造了两次,这个问题留到后面的虚继承会讲到如何解决两次构造的问题

5.多态

1)虚函数

1.声明-virtual关键词

2.用途

解决子类和父类相同原型成员函数的调用问题,通过虚函数可以实现通过基类指针或引用来访问基类和派生类中的同名函数。

继承性:

虚函数可以继承,当一个成员函数被声明为虚函数后,其派生类中的同名函数都自动称为虚函数,但是如果派生类没有覆盖基类的虚函数,则调用时调用基类的函数定义

2)动态绑定

1.不使用虚函数:

#include<bits/stdc++.h>
using namespace std;
 
class A
{
public:
    void print_(){
        cout << "A" << endl;
    }
};
 
class B : public A
{
public:
    void print_(){
        cout << "B" << endl;
    }
};
 
int main(){
    //调用方式1:
    A a;
    B b;
    a.print_(),b.print_();
    cout << "-------------------------------------" << endl;
    //利用基类指针调用
    A * ptr_a = &b;
    ptr_a->print_();
 
    B * ptr_b = &b;
    ptr_b->print_();
    cout << "-------------------------------------" << endl;
    //利用基类引用调用
    A & ref_a = b;
    ref_a.print_();
 
    B & ref_b = b;
    ref_b.print_();
    cout << "-------------------------------------" << endl;
    A * pa = &a;
    pa->print_();
 
    A & ra = a;
    ra.print_();
 
    return 0;
}
 
//A
//B
//-------------------------------------
//A
//B
//-------------------------------------
//A
//B
//-------------------------------------
//A
//A

发现利用基类指针指向派生类,调用同名函数的时候依然是基类,无法实现基类指针对子类同名函数的调用,而虚函数可以实现

2.使用虚函数:

#include<bits/stdc++.h>
using namespace std;
 
class A
{
public:
    virtual void print_(){
        cout << "A" << endl;
    }
};
 
class B : public A
{
public:
    virtual void print_(){
        cout << "B" << endl;
    }
    /* 或者不写virtual
     * void print_(){
           cout << "B" << endl;
       }
    */
};
 
 
 
int main(){
    //调用方式1:
    A a;
    B b;
    a.print_(),b.print_();
    cout << "-------------------------------------" << endl;
    //利用基类指针调用
    A * ptr_a = &b;
    ptr_a->print_();
 
    B * ptr_b = &b;
    ptr_b->print_();
    cout << "-------------------------------------" << endl;
    //利用基类引用调用
    A & ref_a = b;
    ref_a.print_();
 
    B & ref_b = b;
    ref_b.print_();
    cout << "-------------------------------------" << endl;
    A * pa = &a;
    pa->print_();
 
    A & ra = a;
    ra.print_();
 
    return 0;
}
 
//A
//B
//-------------------------------------
//B
//B
//-------------------------------------
//B
//B
//-------------------------------------
//A
//A

可以实现基类指针或者引用访问派生类中的同名函数,只看指针指向谁就访问谁

举个例子:

#include <bits/stdc++.h>
using namespace std;
class CEmployee                                //定义CEmployee类
{
public:
    int m_ID;                                    //定义数据成员
    char m_Name[128];                            //定义数据成员
    char m_Depart[128];                            //定义数据成员
    CEmployee()                                //定义构造函数
    {
        memset(m_Name,0,128);                    //初始化数据成员
        memset(m_Depart,0,128);                //初始化数据成员
    }
    virtual void OutputName()                        //定义一个虚成员函数
    {
        cout << "员工姓名: "<<m_Name << endl;            //输出信息
    }
};
class COperator :public CEmployee                    //从CEmployee类派生一个子类
{
public:
    char m_Password[128];                        //定义数据成员
    void OutputName()                            //定义OutputName虚函数
    {
        cout << "操作员姓名: "<<m_Name<< endl;            //输出信息
    }
};
int main(int argc, char* argv[])
{
    CEmployee *pWorker = new COperator();    //定义CEmployee类型指针,调用COperator类构造函数
    strcpy(pWorker->m_Name,"MR");        //设置m_Name数据成员信息
    pWorker->OutputName();                //调用COperator类的OutputName成员函数
    delete pWorker;                    //释放对象
    return 0;
}
//操作员姓名:MR

3.虚函数的限制:

1)只有类的成员函数才成为虚函数

2)静态成员函数不能是虚函数,因为静态成员函数不受限于某个对象

3)内联函数不能是虚函数,因为内联函数是不能在运行中动态确定其位置的

4)构造函数不能是虚函数,析构函数通常是虚函数

3)虚继承

虚继承可以使得派生类中不存在两个类的复制(前面的Human类的复制)

#include <iostream>
using namespace std;
class CAnimal                                //定义一个动物类
{
public:
    CAnimal()                                //定义构造函数
    {
        cout << "动物类被构造"<< endl;                //输出信息
    }
    void Move()                            //定义成员函数
    {
        cout << "动物能够移动"<< endl;                //输出信息
    }
};
class CBird : virtual public CAnimal            //从CAnimal类虚继承CBird类
{
public:
    CBird()                                //定义构造函数
    {
        cout << "鸟类被构造"<< endl;                //输出信息
    }
    void FlyInSky()                            //定义成员函数
    {
        cout << "鸟能够在天空飞翔"<< endl;            //输出信息
    }
    void Breath()                            //定义成员函数
    {
        cout << "鸟能够呼吸"<< endl;                //输出信息
    }
};
class CFish: virtual public CAnimal            //从CAnimal类虚继承CFish
{
public:
    CFish()                                //定义构造函数
    {
        cout << "鱼类被构造"<< endl;                //输出信息
    }
    void SwimInWater()                        //定义成员函数
    {
        cout << "鱼能够在水里游"<< endl;            //输出信息
    }
    void Breath()                            //定义成员函数
    {
        cout << "鱼能够呼吸"<< endl;                //输出信息
    }
};
class CWaterBird: public CBird, public CFish        //从CBird和CFish类派生子类CWaterBird
{
public:
    CWaterBird()                            //定义构造函数
    {
        cout << "水鸟类被构造"<< endl;                //输出信息
    }
    void Action()                            //定义成员函数
    {
        cout << "水鸟即能飞又能游"<< endl;            //输出信息
    }
};
int main(int argc, char* argv[])                        //主函数
{
    CWaterBird waterbird;                        //定义水鸟对象
    return 0;
}
//动物类被构造
//鸟类被构造
//鱼类被构造
//水鸟类被构造

6.抽象类

1)定义与声明

包含有纯虚函数的类是抽象类

举个例子:

class A
{
public:
    virtual int getAge() = 0;
};

注意:抽象类不能实例化

#include<bits/stdc++.h>
using namespace std;
 
class A
{
public:
    virtual int getAge() = 0;
};
 
int main(){
    A a;
 
    return 0;
}

2)作用-规范接口

子类要想使用必须提供抽象类的实现,也就是纯虚函数的实现,如果不实现的话,子类也是一个抽象类,不能被实例化

举个例子:

#include <bits/stdc++.h>
using namespace std;
class CFigure
{
public:
    virtual double getArea() =0;
};
const double PI=3.14;
class CCircle : public CFigure
{
private:
    double m_dRadius;
public:
    CCircle(double dR)
    {
        m_dRadius=dR;
    }
    double getArea()
    {
        return m_dRadius*m_dRadius*PI;
    }
};
class CRectangle : public CFigure
{
protected:
    double m_dHeight,m_dWidth;
public:
    CRectangle(double dHeight,double dWidth)
    {
        m_dHeight=dHeight;
        m_dWidth=dWidth;
    }
    double getArea()
    {
        return m_dHeight*m_dWidth;
    }
};
int main()
{
    CFigure *fg1;
    fg1= new CRectangle(4.0,5.0);
    cout << fg1->getArea() << endl;
    delete fg1;
    CFigure *fg2;
    fg2= new CCircle(4.0);
    cout << fg2->getArea() << endl;
    delete fg2;
 
    return 0;
}
//20
//50.24

继承与派生入门暂时这么多~~qwq

0

发表评论

电子邮件地址不会被公开。 必填项已用*标注

5 × 4 =