基类与派生类之间的转换
前面我们看到动态绑定发生的两个条件:1.被调用的函数为虚函数。2.通过指向基类的引用或指针调用。
我们是可以让基类的引用或指针指向派生类的,因为派生类都含有其基类作为其的一部分,当有这样的函数形参时,编译器会默认将参数作为基类型,这样是安全的,运行时再根据实参动态绑定。
基类型的引用或指针是静态类型(static type),编译时确定;而它们所指向的内容是动态类型(dynamic type),运行时确定。这也是C++中实现多态的关键。
如果确定是想要调用派生类中基类版本的函数,可以通过作用域符::
base *p=&derived;
p->base::func(); |
这样调用将在编译时确定。
只有成员函数中的代码才应该使用这样的方式。
虚函数也可以拥有默认参数,如果通过动态绑定方式调用这个虚函数时(通过基类的引用或指针),默认参数的值就是基类中定义的,与动态绑定无关,但其它部分是动态绑定的。
class base{
public:
int pub;
virtual void func(int );
};
void base::func(int i=1){
cout<<"i= "<<i<<" in base"<<endl;
}
class derived :public base{
public:
void func(int i=2){
cout<<"i= "<<i<<" in derived"<<endl;
}
}; void f2(base& ref_b){
ref_b.func();
}
int main(void) {
derived obj1;
f2(obj1);
cout<<"end in main\n";
return EXIT_SUCCESS;
}
|
运行结果
i= 1 in derived
end in main |
看到默认参数i的值是基类中确定的1,但其后的输出确是 in derived,动态绑定。
所以虚函数尽量避免使用默认参数。继承方式有三种,公有,保护,私有继承。
基类中的私有成员只有基类的私有成员和它的友元能够访问,哪种派生后的派生类都不能访问。
公有继承中,基类中的成员继续保持它们各自的访问限制。
保护继承中,基类的成员都变为派生类的保护成员。
私有继承中,基类全部成员都变为派生类的私有成员。
实际程序中绝大部分派生都是公有的。
基类的私有成员派生后派生类不能访问,还是就没有继承呢
class base{
public:
int i;
private:
int a;
};
class derived :private base{
public:
};
int main(void) {
derived obj_d;
obj_d.a=1;
obj_d.i=2;
}
|
派生类私有派生,编译错误
`int base::a' is private
`int base::i' is inaccessible
如果去掉现main函数中内容,只在其中输出 sizeof 基类和派生类的值,都是8,说明私有成员也继承了,只是不能访问。
当进行保护或私有派生时,如果我们还想使基类的某个公有成员保持公有的属性,怎么办,使用using语句。
class base{
public:
int i;
private:
int a;
};
class derived :private base{
public: using base::i;
};
int main(void) {
derived obj_d;
obj_d.a=1;
obj_d.i=2;
} |
编译时只会在
obj_d.a=1;这里报错,`int base::a' is private。
using语句只能用于保持(不能放宽)数据成员的原属性,原来的成员在基类是公有的,在派生类中,using语句也得在公有部分出现。
友元与继承
基类的友元可以访问其保护成员和私有成员,但是友元关系是不能随派生让派生类继承的。
静态成员
基类中有静态成员,则即使经过N次派生后,在整个的派生体系中也只有这一个静态成员。
class base{
public:
static int i;
private:
int a;
};
class derived1 :public base{
public:
};
class derived2 :public base{
public:
};
int base::i=0;
int main(void) {
derived1::i=1;
derived2::i=2;
cout<<"base::i= "<<base::i<<endl;
} |
结果为 base::i= 2
阅读(756) | 评论(0) | 转发(0) |