C++之 虚函数的访问控制 以及 编译器的绑定策略
2014-08-15 17:59
225 查看
[updated] 注意:基类的指针不能调用派生类自己定义的函数,只能调用虚函数!!!!因为函数的绑定是静态的,实际调用的函数才是动态的。
如下面的代码:
这里文章的题目是自拟的,只因为自己发现虚函数的访问控制,与自己之前的理解有出入,于是备忘之。
首先,虚函数是实现多态的机制,也就是说在利用基类的指针或者引用调用虚函数时,调用的是该指针或者引用的动态类型的相应的函数,这里有几点需要备忘的。
1 编译器在决定调用函数时,如果该函数是虚函数才会在运行时确定调用什么函数,如果不是虚函数,那么在编译阶段就已经确定了调用的函数类型,如下面的代码;
基类与派生类都声明了函数f。但是在main函数的调用中编译器调用的是静态类型对应的函数,因为f函数并不是虚函数,虽然在基类与派生类中都声明了该函数。
这是显然的,没有虚函数,就没有多态了,也就无所谓动态类型了。函数的所有调用都是静态绑定。
2 基类定义虚函数为public,派生类覆盖了该虚函数,但是将其声明为private,这样当基类的指针绑定到派生类的对象时,使用该基类指针调用该虚函数时,调用是否成功。如果二者的访问权限反过来呢。
上述代码的输出为: f() in derived 0
首先分析,为什么输出结果是f() in derived. 编译器在看到b对f进行调用时,此时编译器根据b的静态类型(也就是Base)来决定f函数是否可访问,由于f函数式public的,OK, "访问控制为public"并没有影响调用,并且进行形参的默认参数的赋值。
由于f是虚函数,那么具体调用哪个函数是在运行时确定的,于是,在运行时查找Derived的虚函数表,得到虚函数f(此时的f已经被Derived类覆盖,于是调用的就是派生类的版本。)
至于,为什么i的值为0,上述分析也已经说明了,也可以参见文章 点击打开链接
如果将两者的访问权限交换,那么访问控制这一关都过不了,其实很简单,既然你需要派生类继承f函数,将其在Base类中声明为private本身就是不对的。
如下面的代码:
//基类的指针不可以调用派生类自身定义的函数(不是虚函数) #include using namespace std; class Base { public: void FuncInBase(){cout << "Func in Base..." << endl;} }; class Derived:public Base { public: void FuncInDerived() {cout << "Func in Derived..." << endl;} }; int main(void) { Base *p = new Derived(); p->FuncInBase(); //Func in Base p->FuncInDerived(); //编译不通过 return 0; }
这里文章的题目是自拟的,只因为自己发现虚函数的访问控制,与自己之前的理解有出入,于是备忘之。
首先,虚函数是实现多态的机制,也就是说在利用基类的指针或者引用调用虚函数时,调用的是该指针或者引用的动态类型的相应的函数,这里有几点需要备忘的。
1 编译器在决定调用函数时,如果该函数是虚函数才会在运行时确定调用什么函数,如果不是虚函数,那么在编译阶段就已经确定了调用的函数类型,如下面的代码;
基类与派生类都声明了函数f。但是在main函数的调用中编译器调用的是静态类型对应的函数,因为f函数并不是虚函数,虽然在基类与派生类中都声明了该函数。
这是显然的,没有虚函数,就没有多态了,也就无所谓动态类型了。函数的所有调用都是静态绑定。
2 基类定义虚函数为public,派生类覆盖了该虚函数,但是将其声明为private,这样当基类的指针绑定到派生类的对象时,使用该基类指针调用该虚函数时,调用是否成功。如果二者的访问权限反过来呢。
class Base { public: virtual void f(int i=0) {cout << "f() in Base..." << i << endl;} }; class Derived:public Base { private: void f(int i=1){cout << "f() in derived..." << i << endl;} }; int main(void) { Base *b = new Derived(); b->f(); return 0; }
上述代码的输出为: f() in derived 0
首先分析,为什么输出结果是f() in derived. 编译器在看到b对f进行调用时,此时编译器根据b的静态类型(也就是Base)来决定f函数是否可访问,由于f函数式public的,OK, "访问控制为public"并没有影响调用,并且进行形参的默认参数的赋值。
由于f是虚函数,那么具体调用哪个函数是在运行时确定的,于是,在运行时查找Derived的虚函数表,得到虚函数f(此时的f已经被Derived类覆盖,于是调用的就是派生类的版本。)
至于,为什么i的值为0,上述分析也已经说明了,也可以参见文章 点击打开链接
如果将两者的访问权限交换,那么访问控制这一关都过不了,其实很简单,既然你需要派生类继承f函数,将其在Base类中声明为private本身就是不对的。
相关文章推荐
- C++基类和派生类私有、保护、公有成员访问控制以及动态绑定、三种继承
- C++之 private public protect访问控制以及继承关系
- c++静态绑定和动态绑定以及虚函数中缺省参数的绑定
- C++虚函数-同名访问 以及两道例题
- C++中struct也有构造函数与析构函数,也可以有访问类型控制以及结构体大小,类大小
- C++成员访问控制,以及C++继承方式对成员访问控制的影响
- C++中struct也有构造函数与析构函数,也可以有访问类型控制以及结构体大小,类大小
- rip ospf + 访问控制策略
- C++ 类访问控制(public/protected/private)
- C++ 类访问控制public/private/protected探讨
- C/C++ 编译器和调试器以及静态库、动态库使用汇总
- 【C/C++】C++中类访问权限控制
- 网络管理员:注重服务器访问权限控制策略
- C/C++ 编译器和调试器以及静态库、动态库使用汇总
- C++的访问权限控制关键字:private / public / protected
- C/C++ 编译器和调试器以及静态库、动态库使用汇总
- C++ 类访问控制public/private/protected探讨
- 关于C++中私有继承后虚函数的访问权限与私有继承后多态的问题
- C++中的控制访问权限
- C/C++ 编译器和调试器以及静态库、动态库使用汇总