类继承中需注意的问题

来源:互联网 发布:美国石油产量数据 编辑:程序博客网 时间:2024/06/02 01:28

【记住】派生类不能直接访问基类的私有成员,而必须通过基类方法进行访问。

       创建派生类对象时,程序首先调用基类的构造函数,然后再调用派生类的构造函数。基类构造函数负责初始化继承的数据成员;派生类构造函数主要用于初始化新增的数据成员。派生类的构造函数总是调用一个基类的构造函数。可以使用初始化列表句法指明要使用的基类构造函数,否则使用默认的基类构造函数。
       派生类对象过期时,程序将首先调用派生类析构函数,然后再调用基类的析构函数。
派生类与基类之间的特殊关系:
1) 派生对象可以使用基类方法,条件是方法不是私有的。
2) 基类指针可以在不进行显示类型转换的情况下指向派生类对象;基类引用可以在不进行显示类型转换的情况下引用派生类对象。但这是单向的,不可将基类对象和地址赋值给派生类引用和指针。
如果某个方法在基类和派生类中都有定义,程序如何决定使用哪个版本?
1) 若程序是通过对象来调用这个方法的话,可根据对象的类型来确定使用哪个版本,即若对象的类型是基类,则使用基类中定义的方法;若对象的类型是派生类,则使用派生类中定义的方法。
2) 若程序时通过引用或指针而不是对象调用这个方法的话,具体应该分以下两种情况:如果没有使用关键字virtual,程序将根据引用类型或指针类型选择方法;如果使用了virtual,程序将根据引用或指针指向的对象类型来选择方法。例如,
       Parent为基类,Child为派生类,方法method()ParentChild中都有定义
       Parent dad;
       Child son;
       Parent &ptr1=dad;
       Parent &ptr2=son;
       ptr1.method( );      //(1)
       ptr2.method( );      //(2)
       如果method()不是virtual型的,则由于引用变量ptr1,ptr2都是Parent类型的,故都将执行Parent中的method()方法;
       如果method()virtual型的,虽然引用变量ptr1,ptr2都是Parent类型的,但由于ptr2引用的是一个Child对象,故(1)式将执行Parent中的method()方法;(2)式将执行Child中的method()方法。
       总结:如果要在派生类中重新定义基类的方法,通常应将基类方法声明为虚拟的。这样,程序将根据对象的类型,而不是引用或指针的类型来选择方法版本。
有关虚函数的注意事项
1) 构造函数
       构造函数不能是虚函数,因为派生类不继承基类的构造函数,所有将类构造函数声明为虚拟的没有任何意义。
2) 析构函数
       析构函数应当是虚函数,除非类不用做基类。通常应给基类提供一个虚拟析构函数,即使它并不需要析构函数。这样,当通过指向对象的基类指针或引用来删除派生对象时,程序首先调用派生类的析构函数,然后调用基类的析构函数,而不仅仅是调用基类的析构函数。
3) 友元
       友元不能是虚函数,因为友元不是类成员,而只有成员才能使虚函数。
4) 没有重新定义
       如果派生类没有重新定义函数,将使用该函数的基类版本。
5) 重新定义隐藏方法
A.      如果重新定义继承的方法,应确保与原来的原型完全相同,但如果返回类型是基类引用或指针,则可以修改为指向派生类的引用或指针(这种例外是新出现的,称为返回类型协变)。
B.      如果基类声明被重载了,则应在派生类中重新定义所有的基类版本。如果只重新定义一个版本,则另外两个版本将被隐藏,派生类对象将无法使用它们。
抽象基类
              抽象基类(ABC)描述的是至少使用一个纯虚函数的接口,从ABC派生出的类将根据派生类的具体特征,使用常规虚函数实现这种接口。纯虚函数的声明的结尾处为=0。当一个类中有纯虚函数的话,则不能创建这个类的对象,包含纯虚函数的类只用作基类。
编写使用对象作为参数的函数时,为什么应按引用而不是按值来传递对象?
1) 这样做是为了提高效率。按值传递对象涉及到生成临时拷贝,即调用复制构造函数,然后调用析构函数。调用这些函数需要时间,复制大型对象比传递引用花费的时间要多得多。如果函数不修改对象,应将参数声明为 const引用。
2) 在继承使用虚函数时,被定义为接受基类引用参数的函数可以接受派生类。
返回对象和返回引用
1) 如果可以不返回对象,则应返回引用,而不是返回对象。原因在于,返回对象涉及到生成返回对象的临时拷贝,故返回对象的时间成本包括调用拷贝构造函数来生成拷贝所需的时间和调用析构函数删除临时拷贝所需的时间。返回引用可节省时间和内存。
2) 不过,并不总是可以返回引用。函数不能返回在函数中创建的临时对象的引用,因为当函数结束时,临时对象将消失,因此这种引用时非法的。在这种情况下,应返回对象,以生成一个调用程序可以使用的拷贝。
通用规则是,如果函数返回在函数中创建的临时对象,则不要使用引用;如果函数返回的是通过引用或指针传递给它的对象,则应按引用返回对象。