如果基类定义有虚成员函数,基类的析构函数一般声明为虚函数(防止子类释放时,父类没有析构,造成内存泄漏)
任何类如果声明有一个(或多个)纯虚函数,那么,由于其接口的不完整性(纯虚函数没有函数定义,是谓不完整),程序无法为它产生任何对象。这种类只能作为派生类的子对象使用,而且前提是这些派生类必须为所有虚函数提供确切的定义。
二、定义一个派生类如果通过基类的接口无法访问子类特有的接口;如果在基类定义上同名的纯虚函数。这样,子类的同名函数就自动成为虚函数——它们不需要再指定关键字virtual。如果子类的函数再加virtual,那么修改父类的对象就要大费周章:每个子类都必须对它重新声明。
三、基类的抽象如果类的数据成员是引用类型,必须在构造函数的初始化列表加以初始化。一旦初始化之后,就再也无法指向另一个对象。
四、初始化、析构、复制当基类有数据成员时,为基类提供构造函数,利用构造函数处理基类所声明的所有数据成员的初始化操作。
一个抽象基类由于无法定义任何对象,其角色是每个子类对象的子对象;因此,我们可以将基类的构造声明为protected。
子类对象的初始化行为,包含调用基类的构造函数,然后再调用自身的构造函数。
子类的构造函数,不仅必须为自身的数据成员进行初始化操作,还要为父类的数据成员提供适当的值。
例如:
inline fib::fib(int len,int pos)
:num_seq(len,pos,elem){
}
拷贝构造时:首先,父类子对象会把逐一初始化,然后子类的成员也会被逐一初始化。
如果我们将某个fib对象赋值给另一个fib对象时,而且fib类拥有明确定义的拷贝赋值操作,它便会再赋值操作时发生调用。以下便是其中一种定义方式,必须明确调用基类的拷贝赋值操作。
fib & fib::operator=(const fib &rhs){
if(this!=&rhs)
//明确调用父类的拷贝赋值操作
num_seq::seq=(rhs);
return *this;
}
五、在派生类中定义一个虚函数
如果决定覆盖基类的所提供的虚函数,那么派生类提供的新定义,其函数原型必须完全符合基类所声明的函数原,包括参数列表、返回类型、常量性(const-ness)。
一般情况下,派生类提供的函数和基类同名函数没有完全吻合,不能覆盖基类的同名函数。但是有种例外——当基类的虚函数返回某个基类形式(通常是pointer或reference)时:
class num_seq{
public:
//派生类的clone函数可以返回一个指针 指向num_seq的任何一个派生类
virtual num_seq *clone()=0;
};
派生类中;的同名函数便可以返回基类所派生出来的类型:
class fib: public num_seq{
public:
//ok fib乃派生自num_seq
//在派生类中 virtual并非必要
fib *clone(){return new fib(*this)}
}
虚函数的静态解析:
有两种情况。虚函数机制不会出现预期行为:(1)基类的构造和析构函数内(2)当我们使用的是基类的对象,而非基类对象的pointer或reference时。
当我们构造派生类对象时,基类的构造函数先被调用,如果此时基类的构造函数调用某个虚函数,一定是其自身的函数,因为此时派生类中的成员函数尚未初始化。
在C++中,唯有用基类的指针和引用才能支持面向对象编程概念。当一个基类声明一个实际对象,但是传入的却是一个派生类对象,属于基类拥有的成员会被保存,基类没有的类型会被切掉。
运行时的类型鉴定机制
typeid运算符,是所谓运行时类型鉴定机制(run time type identification RTTI)的一部分,由程序语言支持。它让我们查询多态的class pointer或class reference,获得其所指对象的实际类型。
#includeinline const char * num_seq:: what_am_i()const { return typeid(*this).name(); }
每一个多态类都对应一个typd_info对象。
static_cast
if(typeid(*ps)==typeid(fib)){
fib * pf=static_cast(ps);//无条件转换
pf->gen_elem(64);
}
static_cast其实有潜在风险,因为编译器无法确认我们所进行的转换操作是否完全正确,这就是 typeid(*ps)==typeid(fib) 使用的原因。
danamic_cast提供有条件的转换,也是RTTI运算符,会进行运行时检验操作,检验ps所指对象是否属于fib类。
if(fib *pf=dynamic_cast答案(ps)) pf->gen_elem(64);
#includeusing namespace std; #include #include #include using namespace std; typedef string elemType; class Stack { public: // Stack(); virtual ~Stack(){} virtual bool pop(elemType &)=0; virtual bool push(const elemType&)=0; virtual bool peek(int index,elemType&)=0; virtual int top() const =0; virtual int size() const =0; virtual bool empty() const =0; virtual bool full() const =0; virtual void print(ostream& =cout ) const=0; }; ostream& operator<<(ostream &os,const Stack &rhs) { rhs.print();return os; } class LIFO_Stack:public Stack{ public: LIFO_Stack(int capacity=0):_top(0){ if(capacity) _stack.reserve(capacity); } int size() const {return _stack.size();} bool empty() const {return !_top;} bool full() const {return size()>=_stack.max_size();} int top() const{return _top;} void print(ostream &os=cout) const; bool pop(elemType &elem); bool push(const elemType& elem); bool peek(int,elemType&){return false;} private: vector _stack; int _top; }; void LIFO_Stack::print(ostream &os) const{ vector ::const_reverse_iterator rit=_stack.rbegin(), rend=_stack.rend(); os<<"nt"; while (rit!=rend) { os<<*rit++<<"nt"; } } bool LIFO_Stack::pop(elemType &elem){ if(empty()) return false; elem=_stack[--_top]; _stack.pop_back(); return true; } bool LIFO_Stack::push(const elemType& elem){ if(full()) return false; _stack.push_back(elem); ++_top; return true; } class Peekback_Stack:public Stack{ public: Peekback_Stack(int capacity=0):_top(0){ if(capacity) _stack.reserve(capacity); } int size() const {return _stack.size();} bool empty() const {return !_top;} bool full() const {return size()>=_stack.max_size();} int top() const{return _top;} void print(ostream &os=cout) const; bool pop(elemType &elem); bool push(const elemType& elem); bool peek(int,elemType&); private: vector _stack; int _top; }; void Peekback_Stack::print(ostream &os) const{ vector ::const_reverse_iterator rit=_stack.rbegin(), rend=_stack.rend(); os<<"nt"; while (rit!=rend) { os<<*rit++<<"nt"; } } bool Peekback_Stack::pop(elemType &elem){ if(empty()) return false; elem=_stack[--_top]; _stack.pop_back(); return true; } bool Peekback_Stack::push(const elemType& elem){ if(full()) return false; _stack.push_back(elem); ++_top; return true; } bool Peekback_Stack::peek(int index,elemType& elem) { if(empty()) return false; if(index<0||index>=size()) return false; elem=_stack[index]; return true; } void peek(Stack &st,int index){ cout< cout<<"peek failed"; } cout< LIFO_Stack st; string str; while (cin>>str&&!st.full()) { st.push(str); if(cin.get()=='n') break; } cout<<'n'<<"about to call peek() with LIFO_Stack"< string t; if(st.pop(t)) pst.push(t); } cout<<"about to call peek() with Peekback_Stack"< #include#include using namespace std; typedef string elemType; class Stack{ public: Stack(int capacity=0):_top(0){ if(capacity) _stack.reserve(capacity); } virtual ~Stack(){} bool pop(elemType &); bool push(const elemType& ); virtual bool peek(int,elemType&) {return false;} int size() const {return _stack.size();} int top() const{return _top;} bool empty() const {return !_top;} bool full() const {return size()>=_stack.max_size();} void print(ostream &os=cout) const; private: vector _stack; int _top; }; class Peekback_Stack: public Stack{ public: Peekback_Stack(int capacity=0):Stack(capacity){} virtual bool peek(int index,elemType& elem); }; int main() { cout << "Hello World!" << endl; return 0; }



