zoukankan      html  css  js  c++  java
  • C++中的关键概念:名字查找与继承

    关键概念:名字查找与继承

    理解 C++ 中继承层次的关键在于理解如何确定函数调用。确定函数调用遵循以下四个步骤:

    1)  首先确定进行函数调用的对象、引用或指针的静态类型。

    2)  在该类中查找函数,如果找不到,就在直接基类中查找,如此循着类的继承链往上找,直到找到该函数或者查找完最后一个类。如果不能在类或其相关基类中找到该名字,则调用是错误的。

    3)  一旦找到了该名字,就进行常规类型检查,查看如果给定找到的定义,该函数调用是否合法。

    4)  假定函数调用合法,编译器就生成代码。如果函数是虚函数且通过引用或指针调用,则编译器生成代码以确定根据对象的动态类型运行哪个函数版本,否则,编译器生成代码直接调用函数。

    class A
    {
    protected:
    	int m_data;
    public:
    	A(int data=0)
    	{
    		m_data = data;
    	}
    	int GetData()
    	{
    		return doGetData();
    	}
    	virtual int doGetData()
    	{
    		return m_data;
    	}
    };
    
    class B: public A
    {
    protected:
    	int m_data;
    public:
    	B(int data = 1)
    	{
    		m_data = data;
    	}
    	int doGetData()
    	{
    		return m_data;
    	}
    };
    
    class C: public B
    {
    protected:
    	int m_data;
    public:
    	C(int data=2)
    	{
    		m_data = data;
    	}
    };
    
    class Base
    {
    public:
    	virtual int fun()
    	{
    		cout << "base: virtual int fun()" << endl;
    		return 0;
    	}
    };
    
    class D1 : public Base
    {
    public:
    	int fun(int)
    	{
    		cout << "D1: int fun(int)" << endl;
    		return 0;
    	}
    	int myfun(int, int)
    	{
    		cout << "Two int" << endl;
    		return 0;
    	}
    };
    
    class D2 : public D1
    {
    public:
    	int fun(int)
    	{
    		cout << "D2: int fun(int)" << endl;
    		return 0;
    	}
    	int fun()
    	{
    		cout << "D2: int fun()" << endl;
    		return 0;
    	}
    	int myfun(int, int, int)
    	{
    		cout << "Three int" << endl;
    		return 0;
    	}
    };
    
    int main()
    {
    	C c(10);
    	cout << c.GetData() << endl;
    	cout << c.A::GetData() << endl;
    	cout << c.B::GetData() << endl;
    	cout << c.C::GetData() << endl;
    	cout << c.doGetData() << endl;
    	cout << c.A::doGetData() << endl;
    	cout << c.B::doGetData() << endl;
    	cout << c.C::doGetData() << endl;
    
    	D2 d2;
    	//d2.myfun(2,2); //“D2::myfun”: 函数不接受 2 个参数。同一个类中定义的函数才可以重载,继承来的不行。
    	d2.myfun(2,2,2);
    
    	getchar();
    	return 0;
    }

    运行结果:

    22

    说明:

         1)成员函数的重载只能发生在同一个类中所定义的若干函数。不能对从父类继承过来的函数进行重载。因为用子类对象调用“重载函数”的时候,名字查找规则首先在子类中进行,结果找到了具有这个名字的函数,不会再向父类继续查找,所以也谈不上重载。(注释处说明了这个问题)

         2)因为D1定义了一个 int fun(int) ,它屏蔽了基类的虚函数 virtual int fun()。从Base继承的虚函数不能通过D1对象(或D1的引用或指针)调用,因为该虚函数被屏蔽了,名字查找规则决定了其在D1中找到了名为fun函数,不会继续向上查找。

         3)对于前面11111011的输出,只解释第一个,后面类似:cout << c.GetData() << endl;

    本来是要调用C类的GetData(),C中未定义,故调用B中的,但是B中也未定义,故调用A中的GetData(),因为A中的doGetData()是虚函数,所以调用B类中的doGetData(),而B类中的doGetData()返回B::m_data,所以输出1。

  • 相关阅读:
    Munge
    file upload custom form
    随笔摘要
    生成css 和 清缓存
    drupal commit 原则
    Git reset --hard
    www-data
    301/302的区别
    什么是request_uri
    in_array foreach array_search的性能比较
  • 原文地址:https://www.cnblogs.com/younes/p/1794357.html
Copyright © 2011-2022 走看看