zoukankan      html  css  js  c++  java
  • ### C++总结-[类的继承]

    面向对象中关于继承的总结。

    #@author:       gr
    #@date:         2015-07-26
    #@email:        forgerui@gmail.com
    

    一、类的隐藏

    重载(overload)、覆盖(override)与隐藏(hidden)。
    重载:
    相同的范围(在同一个类中)
    函数名字相同
    参数不同
    virtual 关键字可有可无

    覆盖(重写):
    不同的范围(分别位于派生类与基类)
    函数名字相同
    参数相同
    基类函数必须有 virtual 关键字

    隐藏:
    如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无 virtual 关键字,基类的函数将被隐藏(注意别与重载混淆)
    如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有 virtual关键字。此时,基类的函数被隐藏,基类有virtual关键字的话就是覆盖了。

    父类是virtual方法          形参表相同  ---> 构成重写
    父类是virtual方法          形参表不同  ---> 隐藏父类方法
    父类不是virtual方法        形参表相同  --->隐藏父类方法
    父类不是virtual方法        形参表不同  --->隐藏父类方法
    

      
    总结:
    重载肯定是在一个域中的,C++不支持跨域重载,即子类同名函数永远不与父类函数形成重载,而是隐藏掉父类同名函数。
    覆盖的要求比较严格,子类与父类只有一种情况构成重写,三种情况下子类与父类同名函数构成隐藏。

    继承类函数会隐藏子类中所有同名的函数,即使是子类中的虚函数也会隐藏所有同名函数,即使将父类的函数声明为virtual都不会改善这种情况。

    class A {
    public:
    	void print() {			//加上virtual不会改善这种情况
    		cout << "hello base class" << endl;
    	}
    };
    
    class B : public A {
    public:
    	void print(int) {		//加上virtual也不会改善这种情况
    		cout << "hello inheritance class" << endl;
    	}
    };
    

    上面的print(int)会隐藏掉所有基类中叫print的函数。

    B b;
    b.print();		//报错,子类的该函数已被隐藏
    

    如果想要调用A中的函数,需要使用类作用域来限定:

    B b;
    b.A::print();		//类作用域调用
    

    除此之外,还可以在子类中使用using声明基类函数,如下:

    class B : public A {
    public:
    	using A::print;			//注意这里没有括号
    	void print(int) {
    		cout << "hello inheritance class" << endl;
    	}
    };
    

    二、多态实现

    普通函数表现在静态绑定上,即根据当前类类型决定调用函数,而不是实际的对象类型。如下:

    class A {
    public:
    	void print() {
    		cout << "hello base class" << endl;
    	}
    };
    
    class B : public A {
    public:
    	void print() {
    		cout << "hello inheritance class" << endl;
    	}
    };
    
    void main() {
    	A* pA = new B();
    	pA->print();			//此句会调用A::print()
    }
    

    上面pA只会调用A类的print()函数,如果我们想根据实际对象的类型来调用相应的函数,那么就需要进行动态绑定。将基类的print()函数声明为virtual,可以解决这个问题。

    class A {
    public:
    	virtual void print() {
    		cout << "hello base class" << endl;
    	}
    };
    class B : public A {
    public:
    	void print() {
    		cout << "hello inheritance class" << endl;
    	}
    };
    
    void main() {
    	A* pA = new B();
    	pA->print();			//根据对象的实际类型调用B::print()
    }
    

    虚函数的成本:

    当然,"天下没有免费的午餐"。实现这种功能必须花费一定的成本。
    一般函数是不会增加对象空间的,一般C++对象的大小由非静态成员变量,虚函数,以及对齐决定。

    而使用虚函数,主要有两个成本

    1. 一个类会在内存中建立一个虚函数表(vtbl),用来记录虚函数信息,所有该类对象共享该虚函数表。类的虚函数表是一块连续的内存,每个内存单元中记录一个JMP指令的地址,也就是每个函数的地址。
    2. 其次,会在每个类对象内增加一个指针(vptr, 32位的话占用4个字节),用以指向虚函数表。

    因为基类、子类有两个不同的虚函数表,且两个虚函数指针指向各自的虚函数表,所以在运行时可以体现出多态。同理,如果作为函数参数,不能以值传递,这样对象会被slice,必须传递指针或引用。虚函数需要在运行时才能确定运行的函数,但在编译时就要给出可以执行的命令,主要是如下几步:

    1. 根据pC1所指对象的虚函数指针(vptr)索引到虚函数表(vtbl)。
    2. 在虚函数表中找到函数的偏移,记为i。
    3. 调用第二步中的函数,*(pC1->vptr[i])(pC1);

    三、类的权限控制

    1. 继承方式

      public继承: public => public, protect =>protect, private => 不可访问
      protect继承:public => protect, protect =>protect, private => 不可访问
      private继承:public => private, protect => private, private => 不可访问

    2. 子类成员

      public成员:public => public, protect => protect, private => private
      protect成员:public => protect, protect => protect, private => private
      private成员:都不可访问

    默认继承方式是private继承(所以如果需要使用子类成员,需要public继承),默认成员是private。

    四、虚基类

    含有纯虚函数的类叫做虚基类,类似Java里的接口(interface)。虚基类无法被实例化,只能通过继承,实现子类。

    class AbstractBase {
    public:
    	virtual void solve() = 0;         //纯虚函数
    	virtual ~AbstractBase(){}
    };
    class Derivation : public class AbstractBase {
    public:
    	void solve(){}
    };
    
    int main() {
    	AbstractBase* thing = new Derivation();
    	thing->solve();
    }
    

    五、继承与组合

    继承是is a关系,组合是has a关系。有时需要根据事实正确塑模出其关系。

    六、多继承与虚继承

    为了满足一个类包含两个类的性质,C++提供多继承。
    为了解决多继承带来的包含多个基类问题,使用虚继承,可以只包含一个基类。

    class A {};
    class B1 : virtual public A {};    //虚继承
    class B2 : virtual public A {};    //虚继承
    class C : public B1, public B2 {}; //使用虚继承,C中只包含一个A
  • 相关阅读:
    while语句
    闭包
    文件操作
    Python基础九:高级特性
    Python基础八:函数
    Python基础六:字典和集合
    Python基础七:条件判断和循环结构
    Python基础五:列表和元组
    Python基础四:字符串及编码
    Python基础三:数据类型和变量
  • 原文地址:https://www.cnblogs.com/gr-nick/p/4811466.html
Copyright © 2011-2022 走看看