The code: has made calls to private member via object pointer

JoshuaLi 2003-01-05 09:04:28
#include <iostream>
using std::cout;
using std::endl;

class A
{
public:
virtual void foo1(){cout<<"A::foo1()"<<endl;}
private:
virtual void foo(){cout<<"A::foo()"<<endl;}
};

class B:private A
{
private:
virtual void foo1(){cout<<"B::foo1()"<<endl;}
public:
virtual void foo(){cout<<"B::foo()"<<endl;}
};

int main()
{
B b;
A *a=(A *)&b;
a->foo1();

A a1;
B *b1=(B *)&a1;
b1->foo();

return 0;
}


/*
The code above makes calls to private member via object pointer, pls explain why.

This question is mentioned first in the following link, thank the original initiator.

http://expert.csdn.net/Expert/topic/1307/1307940.xml?temp=.5337946
*/
...全文
30 5 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
JoshuaLi 2003-01-07
  • 打赏
  • 举报
回复
#include <iostream>
using std::cout;
using std::endl;

class A
{
public:
/*virtual*/ void foo1(){cout<<"A::foo1()"<<endl;}
private:
/*virtual*/ void foo(){cout<<"A::foo()"<<endl;}
};

class B : private A
{
private:
/*virtual*/ void foo1(){cout<<"B::foo1()"<<endl;}
public:
/*virtual*/ void foo(){cout<<"B::foo()"<<endl;}
};

int main()
{
B b;
A *a=reinterpret_cast<A *>(&b);
a->foo1();

A a1;
B *b1=reinterpret_cast<B *>(&a1);
b1->foo();

return 0;
}

/*
如果去掉Virtual结果又是怎样?

去掉Virtual便进行早绑定

output (vc6):
A::foo1()
B::foo()
Press any key to continue
*/
JoshuaLi 2003-01-05
  • 打赏
  • 举报
回复
"...发现class A 中的fool()是public,ok,可以访问!接着它又发现fool()是virtual function,于是编译器决定执行动态绑定,将this指针入栈..."

说得真好,学习
myjirong 2003-01-05
  • 打赏
  • 举报
回复
访问控制权由指针或引用的静态类型决定,而实际调用哪个成员函数由对象的实际类型决定!
merlinran 2003-01-05
  • 打赏
  • 举报
回复
从这里明白了为何C++导师们都劝我们要用C++风格的类型转换而不要用C风格的。如果用C++风格的转换,就只有reinterpret_cast<>行得通,而且看起来极不顺眼,大家都知道那是危险的。而用C风格的转型,MingW上居然连一个warning都没有!如果是在一个实际的系统里,查错不把你查死才怪呢。
chinajiji 2003-01-05
  • 打赏
  • 举报
回复
关键是看这一句:
a->foo1();//现在a 的静态类型是A*,它实际指向的是一个B类型的对象.

编译器看到a时只知道 a 是指向A类型对象的指针, 并不知道它指向的实际类型,于是编译器在class A中找成员函数fool(),它找到了,接着编译器检查成员函数fool()的访问控制权,发现class A 中的fool()是public,ok,可以访问!接着它又发现fool()是virtual function,于是编译器决定执行动态绑定,将this指针入栈,即将a的值入栈,而 a 的值就是b 的地址:&b,也就是说将 &b入栈,再通过&b找到vptr(vptr在对象中的位置由于编译器的具体实现决定),通过vptr找到vtable,vtable是一个指向虚函数的指针数组,通过虚函数名fool找到指向向fool函数的指针值,在通过这个指针调用实际的fool函数,也就是b.fool,这就是大名鼎鼎的"动态绑定",最关键的是此是不会再次检测实际调用的fool成员函数的访问控制权!也就是说,访问控制权只在编译期有作用,运行期没有作用,因为vtable里没有与访问控制权有关的信息,如果我们将这类信息加入vtable,并在运行时检查访问控制权,不仅会增加vtable的数据存储量,还会影响virtual function的运行效率,virtual function带来的负担已经让C++受到了一些人的指责了,如果再加上访问控制权的负担,将会使C++苦不堪言,再说,编译期已经检测了访问控制权,为何又要检查一次呢?如果出现楼主给出程序中的"异常",只能说明程序设计是怪异的.

对于:B *b1=(B *)&a1;
b1->foo();
分析同上;
在VC6.0中下面两个语句将出警告:
A *a=(A *)&b;//原因是private 继承,它是一种"基于实现"的继承,不是"is- //a"继承
B *b1=(B *)&a1;
因为这种类型转换是"粗暴"的,
如果这样:
A *a = reinterpret_cast<A *> (&b);
     B *b1 = reinterpret_cast<B *> (&a1);
就不会出现警告.

16,548

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧