——派生类需要自己的构造函数。
派生类中可以根据需要添加额外的数据成员和成员函数,甚至可以给予继承的原成员函数新的定义。
基类指针或引用可指向派生对象,反过来则只能使用强制类型转换。
派生类对象可使用基类的非私有成员。
可使用派生对象初始化基类对象或赋值。
一般不允许将基类对象赋给派生类对象(上面第三条),特殊情况下可以。
已有派生类对象初始化创建的派生类对象。
已有派生类对象给另一个派生类对象赋值。
派生类对象的析构函数被调用后会自动调用基类的析构函数。
C++11增加了允许继承构造函数的机制,但派生类默认不能继承构造函数和析构函数。
class RatedPlayer : public TableTennisPlayer { private: unsigned int rating; // add a data member public: RatedPlayer (unsigned int r = 0, const string &fn = "none", const string &ln = "none", bool ht = false); RatedPlayer (unsigned int r, const TableTennisPlayer &tp); unsigned int Rating() const { return rating; } // add a method void ResetRating (unsigned int r) { rating = r; } // add a method };
构造函数必须给新成员和继承的成员提供数据。
RatedPlayer::RatedPlayer(unsigned int r, const string &fn, const string &ln, bool ht) : TableTennisPlayer(fn, ln, ht) { rating = r; }
- 派生类构造函数必须使用基类构造函数,创建派生类对象时,程序首先创建基类对象(初始化继承的数据成员)然后再调用派生类构造函数。C++使用成员初始化列表语法完成该操作。
- 如没有调用基类构造函数,那么将隐式调用基类的默认构造函数。除非要使用默认构造函数,否则应显示调用正确的基类构造函数。
派生类对象过期时,程序将首先调用派生类析构函数,然后再自动调用基类析构函数。
要使用派生类,程序必须要能访问基类声明。
派生类对象可以使用基类的方法,条件是方法不是私有的(即公有和保护)。
基类指针可以在不进行显示类型转换的情况下指向派生类对象;基类引用可以在不进行显示类型转换的情况下引用派生类对象
RatedPlayer rplayer(1140, "Mallory", "Duck", true); TableTennisPlayer &rt = rplayer; TableTennisPlayer *pt =&rplayer; rt.Name(); // invoke Name() with reference pt->Name(); // invoke Name() with pointer
不可以将基类对象和地址赋给派生类引用和指针,除非使用强制转换(友元函数不是成员函数因此不能被继承,但欲使用基类的友元函数时可使用此方法,但要小心用错)。
基类声明的函数引用参数或指针参数可用于值为基类对象或派生类对象以及它们的地址的情况。
void Show(const TableTennisPlayer &rt) { ... }
TableTennisPlayer player1("Tara", "Boomdea", false); RatedPlayer rplayer1(1140, "Mallory", "Duck", true); Show(player1); // works with TableTennisPlayer argument Show(rplayer1); // works with RatedPlayer argument
省略形参为const TableTennisPlayer *rt的情况,与上相似。
引用兼容性属性:可以将基类对象初始化为派生类对象。
RatedPlayer olaf1(1840, "Olaf", "Loaf", true); TableTennisPlayer olaf2(olaf1);
匹配的构造函数的原型:
TableTennisPlayer(const RatedPlayer &); // doesn't exit
类中并没有该构造函数,但存在隐式复制构造函数:
// implicit copy constructor TableTennisPlayer(const TableTennisPlayer &);
即它将olaf2初始化为嵌套在RatedPlayer对象olaf1中的TableTennisPlayer对象(使用派生类中嵌套的基类对象对目标基类对象进行初始化)
同样,也可以将派生对象赋给基类对象:
RatedPlayer olaf1(1840, "Olaf", "Loaf", true); TableTennisPlayer winner; winner = olaf1; // assign derived to base object
在这种情况下,程序使用隐式重载赋值运算符:
TableTennisPlayer &operator=(const TableTennisPlayer &) const;
与上类似,使用派生类中嵌套的基类对象对目标基类对象进行按成员赋值。
特殊的用基类对象给派生类对象赋值的情况
如果派生类包含了将基类对象转换为派生类对象的构造函数,或派生类定义了将基类对象赋给派生类对象的赋值运算符,则可以用派生类对象给基类对象赋值。
用已有的派生类对象初始化创建的派生类对象
复制类成员或继承的类组件时,则是使用该类的复制构造函数完成的,对于继承的基类对象来说也是合适的。
用已有的派生类对象给另一个派生类对象赋值
按成员赋值,调用类成员赋值运算符,使用基类的赋值运算符来对基类组件(继承的基类对象)进行赋值
若派生类使用了动态内存分配,派生类的析构函数、复制构造函数、复制运算符都必须使用相应的基类方法来处理基类元素(显示调用基类构造函数和复制运算符):
- 对于析构函数,这是自动完成的。
- 对于复制构造函数,这是在初始化成员列表中调用基类的复制构造函数来完成的;如果不这么做,将自动调用基类的默认构造函数。
- 对于复制运算符,这是通过使用作用域解析运算符显示地调用基类的赋值运算符来完成的:
hasDMA &hasDMA::operator=(const hasDMA &has) { if (this == &hs) return *this; baseDMA::operator=(hs); // copy base portion ... return *this; }
---