C++ 继承是C++的一个重要概念,以前一直以为自己对继承概念理解了,今天做了一个C++继承的题,才发现自己知识点的盲区,现在先上题,有兴趣的可以做下:

main.cpp
#include <QtCore/QCoreApplication>
#include <QDebug>


class A{
    protected:
    int m_data;
    public:
    A(int data = 0)
    {
        m_data= data;

    }

    int GetData()
    {

        return doGetData();
    }

    virtual int doGetData()
    {

        return m_data;
    }

//    int doGetData()
//    {
//        //qDebug ()<<"virtual data is "<<m_data;
//        return m_data;
//    }
};

class B:public A{

    protected:
    int m_data;
    public:
    B(int data = 1)
    {
        m_data= data;
    }
    int GetData ()
    {
        return m_data;
    }
    int doGetData ()
    {
        return m_data;
    }


};

class C:public B{

protected:
    int m_data;
    public:
    C(int data = 2)
    {
        m_data = data;

    }

};



int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    C c(10);
    qDebug ()<<"c.GetData is "<<c.GetData ();
    qDebug ()<<"c.A::GetData is "<<c.A::GetData ();
    qDebug ()<<"c.B::GetData is "<<c.B::GetData ();
    qDebug ()<<"c.C::GetData is "<<c.C::GetData ();
    qDebug ()<<"c.doGetData is "<<c.doGetData ();
    qDebug ()<<"c.A::doGetData is "<<c.A::doGetData ();
    qDebug ()<<"c.B::doGetData is "<<c.B::doGetData ();
    qDebug ()<<"c.C::doGetData is "<<c.C::doGetData ();

    return a.exec();
}

写出main 函数里面qDebug中打印的值,各位不妨先思考下再看答案
答案是:

c.GetData is  1 
c.A::GetData is  1 
c.B::GetData is  1 
c.C::GetData is  1 
c.doGetData is  1 
c.A::doGetData is  0 
c.B::doGetData is  1 
c.C::doGetData is  1 

首先,记住先说下我的理解:
(1)调用的成员函数的时候,会首先去本类里面去寻找成员函数,如果没有找到则会向自己的父类寻找,去调用父类的成员函数。
(2)当调用的成员函数前面有类的描述符的时候,则会去调用类描述符的那个类的成员函数。
(3)当类成员种调用虚函数的时候,会调用派生类中虚函数的最后的实现
上面的话理解不了没关系,我们一个一个来看
C c(10); 派生类的构造函数,回去自动去调用父类的构造,这个没问题吧,调用顺序C->B->A。
所以现在A::m_data=10;B::m_data=2;C::m_data=10;

  • qDebug ()<<"c.GetData is "<<c.GetData ();看下这个调用顺序,c中没有GetData,则会去找父类B的成员函数,父类中有这个函数,直接返回 所以是1.如果父类B中也没这个函数,那么会继续往上找,会找到A的GetData,A中的GetData 调用的是个虚函数,看上面的第一条,A会去找他派生类中的实现,所以最后还是会调用B中的实现,输出1.
  • qDebug ()<<"c.A::GetData is "<<c.A::GetData (); 看第二个,函数前面有类的描述符A,则会去直接调用A的成员函数,然后A成员函数里面有个虚函数,那么他会找到派生类中最后的实现,所以调用的B中的实现,输出1,如果C中也有doGetData,那么则会调用的是C中的doGetData;

  • qDebug ()<<"c.B::GetData is "<<c.B::GetData ();看第三个,函数前面有类的描述符,则会直接去找B的成员函数,返回1

  • qDebug ()<<"c.C::GetData is "<<c.C::GetData (); 函数前面有类的描述符,会去找C里面的成员函数,因为C里面没有这个成员函数,则会向父类去找,返回B里面的值1.
  • qDebug ()<<"c.doGetData is "<<c.doGetData (); 调用B里面的成员函数
  • qDebug ()<<"c.A::doGetData is "<<c.A::doGetData (); 直接调用A的成员函数
  • qDebug ()<<"c.B::doGetData is "<<c.B::doGetData (); 调用B
  • qDebug ()<<"c.C::doGetData is "<<c.C::doGetData (); 调用B的

这是一个很有意思的问题,在这里整理下,如果看完还是不太理解,可以去掉virtual修饰符,看看是怎么样的输出。

发表评论

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