一个多重继承的类:
Class Satellite:public Task,public Displayed{
//...
Void pending();
Void draw();
};
如果两个基类有名字相同的函数:
Class Task{
//...
Virtual debug_info* get_debug();
Virtual void pending()=0;
};
Class Displayed{
//...
Virtual void draw()=0;
Virtual debug_info* get_debug();
};
对于Satellite类来说,使用的时候必须确定使用的是哪个基类的函数:
Void f(Satellite *sp)
{
Debug_info* dip=sp->get_debug(); //error:ambiguous
Dip=sp->Task::get_debug();//ok
Dip=sp->Displayed::get_debug(); //ok
}
使用这种显式区分的方法显然比较累赘,所以可以在satellite类中定义一个新函数:
Class Satellite:public Task,public Displayed{
//...
Debug_info* get_debug() //覆盖了两个基类的相应函数
{
Debug_info* dip1=Task::get_debug();
Debug_info* dip2=Displayed::get_debug();
Return dip1->merge(dip2);
}
};
像Telsatr::draw这样使用修饰符的调用要么调用的是Telstar本身定义的draw函数,要么从Telstar的基类中寻找draw函数:
Class Telstar:public Satellite{
Void draw()
{
Draw(); //oops!:recursive call
Satellite::draw();
Displayed::draw();
Satellite::Displayed::draw();
}
};
这里可以看到,没有类限定符修饰的调用将调用本身的成员函数,而用类限定副修饰的调用,则首先会在所限定的类中寻找,如果没有,再到该类的基类中寻找。
对于函数的重载的解析不会跨类进行,因此对于不同的基类中的同名函数,不会通过函数参数来确定调用哪一个类中的哪一个函数:
Class Task{
//...
Void debug(double p);
};
Class Displayed{
//...
Void debug(int v);
};
Class Satellite:public Task, public Displayed{
//...
};
Void g(Satellite *p)
{
P->debug(1); //error:ambiguous
P->Task::debug(1); //ok
P->Displayed::debug(1); //ok
}
如果一定需要通过函数参数来确定调用的函数,那么:
Class A{
Public:
Int f(int);
Char f(char);
};
Class B{
Public:
Double f(double);
};
Class AB:public A,public B{
Public:
Using A::f;
Using B::f;
Char f(char); //hides a::f(char)
AB f(AB);
};
Void g(AB &ab)
{
Ab.f(1); //A::f(int)
Ab.f('a'); //AB::f(char)
Ab.f(2.0); //B.f(double)
Ab.f(ab); //AB.f(AB)
}
需要注意的是这里AB::f(char)是隐藏了A::f(char),也就是说这两个函数除了同名没有别的关系,因为A::f(char)并非虚函数,不存在覆盖的问题,应该说覆盖也是一种隐藏,但是隐藏不必是覆盖,当然如果这里把A::f(char)声明为虚函数也并不影响这个例子的理解。另一方面如果没有这个函数,调用ab.f('a')的时候就会调用A::f(char),using A::f的作用就在于此。
在类定义中出现的using-declaration必须指向基类的成员,不能指向这个类之外的其他类的成员,包括是派生类的成员,或者这些类的成员函数。
而using-derective不能出现在类定义中,也不能对类使用,只能用在名字空间上。
如果:
Struct Link{
Link* next;
//...
};
Class Task: public Link{
//...
};
Class Displayed:public Link{
//...
};
这样是没有问题的,对于一个satellite对象,会有两个不相关的Link对象,两个列表也不会相互干涉。但是必须这样用:
Void mess_with_links(Satellite *p)
{
P->next=0; //error
P->Link::next=0; //error
P->Task::next=0; //ok
P->Displayed::next=0;//ok
}
函数覆盖的概念在replicated基类里也是存在的:
Class Storable{
Public:
Virtual const char* get_file()=0;
Virtual void read()=0;
Virtual void write()=0;
Virtual ~Storable() {}
};
Class Transmitter:public Storable{
Public:
Void write(); //覆盖基类虚函数
//...
};
Class Receiver:public Storable{
Public:
Void write();
//...
};
Class Radio:public Transmitter, public Receiver{
Public:
Const char* get_file();
Void read();
Void write();
//...
};
to be continued...