![]() |
#2
长江浪打浪2012-02-24 19:09
|

#include <iostream>
using namespace std;
class Father
{
public:
void eat()
{
cout<<"父亲喜欢吃米饭"<<endl;
}
void smoking()
{
cout<<"喜欢抽烟"<<endl;
}
private:
int weight;
int age;
};
class Son :public Father
{
public:
void eat()
{
cout<<"儿子喜欢吃粉"<<endl;
}
};
int main()
{
Son s;
s.eat();
return 0;
}
输去: 儿子喜欢吃粉
这里只是输去子类eat 而父亲的eat 到哪里去了呢!
父亲的子类被儿子的隐藏了。你可以把 s.eat(); 换成 s.Faher::eat();显示调用父类的eat;
就算你你把子类的eat() 换成 eat(int); 然后在
int main()
{
Son s;
s.Father::eat(1);
s.eat();
return 0;
}
会发生编译错误。
说你s.eat() 不能添加参数.
说明你不能调用父类的eat 你改成s.Father::eat(); 就可以了。
这就是隐藏了。
-----------------------------------------------------------
父类 和子类的内存模型
父类: 父类
子类: 父类 + 子类外加部分
他们首地址是一样的。
可以通过
#include <iostream>
using namespace std;
class Father
{
public:
void eat()
{
cout<<"父亲爱吃米饭"<<endl;
}
void show()
{
cout<<"父亲内存地址:"<<this<<endl;
}
};
class Son:public Father
{
public:
void eat()
{
cout<<"儿子爱吃粉"<<endl;
}
void show1()
{
cout<<"儿子内存地址:"<<this<<endl;
}
};
int main()
{
Son s;
s.show1();
s.show();
return 0;
}
儿子内存地址:0012FF7C
父亲内存地址:0012FF7C
Press any key to continue
如果你把Main 改成下面
int main()
{
Son s;
Father *pF;
pF = &s;
pF->eat();
return 0;
}
输去结果会是下面
父亲爱吃米饭
Press any key to continue
为什么会这样呢!! 把一个子类地址传递给父类指针可以调用成功呢!
我来说明一下:
1: 静态绑定 和run-time(运行)绑定。
静态绑定:在编译的时候就确定好了关系, 确定好了你要调用哪个函数,
就像c 语言中的数组大小是在编译的时候就确定 ,是不能够动态改变大小的。
静态编译是通过你的数据类型来来确定的,就像sizeof() 来判断大小是根据你定义的数据类型来判断你的大小。如果你强制转换把一个类型转换另一个类型的时候,可以骗过编译器但你运行的时候就会报错。
动态编译:
根据你给他对象的类型来确定的。。。
2:这里就要用用到子类和父类的首地址一样。
可以说父类的前面部分和子类的部分相同 你真好用的父类指针 所以偏移量是一样的 所以这样才会真好调用父类eat();
这里指针不一样偏移量是不一样的。。
int main()
{
Son s;
Father f;
Son *pS = (Son *)&f;
pS->eat();
return 0;
}
也可以通过这个上面的函数反正明那个事实
using namespace std;
class Father
{
public:
void eat()
{
cout<<"父亲喜欢吃米饭"<<endl;
}
void smoking()
{
cout<<"喜欢抽烟"<<endl;
}
private:
int weight;
int age;
};
class Son :public Father
{
public:
void eat()
{
cout<<"儿子喜欢吃粉"<<endl;
}
};
int main()
{
Son s;
s.eat();
return 0;
}
输去: 儿子喜欢吃粉
这里只是输去子类eat 而父亲的eat 到哪里去了呢!
父亲的子类被儿子的隐藏了。你可以把 s.eat(); 换成 s.Faher::eat();显示调用父类的eat;
就算你你把子类的eat() 换成 eat(int); 然后在
int main()
{
Son s;
s.Father::eat(1);
s.eat();
return 0;
}
会发生编译错误。
说你s.eat() 不能添加参数.
说明你不能调用父类的eat 你改成s.Father::eat(); 就可以了。
这就是隐藏了。
-----------------------------------------------------------
父类 和子类的内存模型
父类: 父类
子类: 父类 + 子类外加部分
他们首地址是一样的。
可以通过
#include <iostream>
using namespace std;
class Father
{
public:
void eat()
{
cout<<"父亲爱吃米饭"<<endl;
}
void show()
{
cout<<"父亲内存地址:"<<this<<endl;
}
};
class Son:public Father
{
public:
void eat()
{
cout<<"儿子爱吃粉"<<endl;
}
void show1()
{
cout<<"儿子内存地址:"<<this<<endl;
}
};
int main()
{
Son s;
s.show1();
s.show();
return 0;
}
儿子内存地址:0012FF7C
父亲内存地址:0012FF7C
Press any key to continue
如果你把Main 改成下面
int main()
{
Son s;
Father *pF;
pF = &s;
pF->eat();
return 0;
}
输去结果会是下面
父亲爱吃米饭
Press any key to continue
为什么会这样呢!! 把一个子类地址传递给父类指针可以调用成功呢!
我来说明一下:
1: 静态绑定 和run-time(运行)绑定。
静态绑定:在编译的时候就确定好了关系, 确定好了你要调用哪个函数,
就像c 语言中的数组大小是在编译的时候就确定 ,是不能够动态改变大小的。
静态编译是通过你的数据类型来来确定的,就像sizeof() 来判断大小是根据你定义的数据类型来判断你的大小。如果你强制转换把一个类型转换另一个类型的时候,可以骗过编译器但你运行的时候就会报错。
动态编译:
根据你给他对象的类型来确定的。。。
2:这里就要用用到子类和父类的首地址一样。
可以说父类的前面部分和子类的部分相同 你真好用的父类指针 所以偏移量是一样的 所以这样才会真好调用父类eat();
这里指针不一样偏移量是不一样的。。
int main()
{
Son s;
Father f;
Son *pS = (Son *)&f;
pS->eat();
return 0;
}
也可以通过这个上面的函数反正明那个事实