如果基类定义有虚成员函数,基类的析构函数一般声明为虚函数(防止子类释放时,父类没有析构,造成内存泄漏)
任何类如果声明有一个(或多个)纯虚函数,那么,由于其接口的不完整性(纯虚函数没有函数定义,是谓不完整),程序无法为它产生任何对象。这种类只能作为派生类的子对象使用,而且前提是这些派生类必须为所有虚函数提供确切的定义。
如果通过基类的接口无法访问子类特有的接口;如果在基类定义上同名的纯虚函数。这样,子类的同名函数就自动成为虚函数——它们不需要再指定关键字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,获得其所指对象的实际类型。
#include
inline 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<fib *>(ps);//无条件转换
pf->gen_elem(64);
}
static_cast其实有潜在风险,因为编译器无法确认我们所进行的转换操作是否完全正确,这就是 typeid(*ps)==typeid(fib) 使用的原因。
danamic_cast提供有条件的转换,也是RTTI运算符,会进行运行时检验操作,检验ps所指对象是否属于fib类。
if(fib *pf=dynamic_cast<fib *>(ps))
pf->gen_elem(64);
#include
using 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<elemType> _stack;
int _top;
};
void LIFO_Stack::print(ostream &os) const{
vector<elemType>::const_reverse_iterator rit=_stack.rbegin(),
rend=_stack.rend();
os<<"\n\t";
while (rit!=rend) {
os<<*rit++<<"\n\t";
}
}
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<elemType> _stack;
int _top;
};
void Peekback_Stack::print(ostream &os) const{
vector<elemType>::const_reverse_iterator rit=_stack.rbegin(),
rend=_stack.rend();
os<<"\n\t";
while (rit!=rend) {
os<<*rit++<<"\n\t";
}
}
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;
}
/*
* 非成员函数peek接受一个“抽象类stack的引用”作为参数,
* 并在函数内调用该stack对象的虚函数peek
*
*/
void peek(Stack &st,int index){
cout<<endl;
string t;
if(st.peek(index,t))
cout<<"peek: "<<t;
else {
cout<<"peek failed";
}
cout<<endl;
}
int main()
{
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"<<endl;
peek(st,st.top()-1);
cout<<st;
Peekback_Stack pst;
while (!st.empty()) {
string t;
if(st.pop(t))
pst.push(t);
}
cout<<"about to call peek() with Peekback_Stack"<<endl;
peek(pst,pst.top()-1);
cout<<pst;
cout << "Hello World!" << endl;
return 0;
}
#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<elemType> _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;
}