to Wolf0403(完美废人)(期待有一天) 难得在java版也能看见C++的题,当然要凑凑热闹了
#include<iostream.h> class A{ public: virtual void show(int a){cout<<"A: a="<<a<<endl; } virtual void show(char *sj){cout<<"A: a=dfgdfgdfg"<<sj<<endl; } }; class B:public A { public: void show(int b){ cout<<"B: b="<<b<<endl; } }; class C:public B { public: void show(int c=999){ cout<<"C: c="<<c<<endl; } }; class D:public C { public: void show(char *sj){ cout<<"D:\ndfgdfgdfgdfg"; } }; void main() { A a,*pa=&a; B b; C c; D d; pa=&b; pa->show(77); pa=&c; pa->show(771); pa=&d; pa->show("effdf");} 改一下你的程序,请大家看看输出是什么?
考java程序员怎么出了C++?? 不会 郁闷
SCJP也有类似的!不如更合适!懒得看cpp
B:b=77 C:c=771 D: dfgdfgdfgdfg
bluesmile979(笑着)和oyd(cpp<JavaIsNotPlatform_Independent>)(MVP)都说得很好,小弟我来补充完整。首先明确两个概念:静态型别(static type)和动态型别(dynamic type) 1. An object's static type is the type you declare it to have in the program text. Consider this class hierarchy 在我们这个例子里,指针pa的静态型别是A*。 2. An object's dynamic type is determined by the type of the object to which it currently refers. That is, its dynamic type indicates how it will behave. 在这个例子里,pa=&b; pa=&c; pa=&d;执行完后,代表指针pa的动态型别分别是B*,C*和D*。下面分析一下4个类中的同名函数show: void A::show(int a=145); void B::show(int b); void C::show(int c=999); void D::show(); 毋庸置疑,类A是B、C、D的基类,所以A中定义的show由其声明可知是一个虚函数。 B::show和C::show由于参数数量和类型与A::show相同,故由类的公有继承可知,它们仍然是虚函数。只是此3个虚函数分别代表3个不同的版本。 D::show不同上面3个,因为其参数类型实际上是void,故它与其父类传承下来的那个虚函数show没有关系,不过是类D相对父类新增的一个show的重载版本,由于声明中没有virtual,所以,它是个非虚函数。最后明确至关重要的一点:虚函数是动态绑定(dynamically bound)而缺省参数是静态绑定(statically bound)的。 在编译期,由于静态绑定只作用于静态型别上(这点很容易理解,因为动态型别只有运行时期才知道),故在程序中凡是涉及到使用含缺省参数的函数的语句,都只能与使用该语句的对象指针的静态型别的那个版本的缺省参数绑定:在这个例子中,pa=&c; pa->show();实际上只能与A::show的缺省参数145绑定。下面,程序开始运行,我们开始分析: pa=&b; // pa的静态型别是A*,动态型别是B* pa->show(77); // 没有涉及到缺省参数,编译期不静态绑定。 运行时动态绑定到B::show,故答案为B: b=77pa=&c; // pa的静态型别是A*,动态型别是C* pa->show(); // 涉及缺省参数,编译期静态绑定A::show的缺省参数145(编译器根本没看999)。 运行时动态绑定到C::show,故答案为C: c=145pa=&d; // pa的静态型别是A*,动态型别是D* pa->show(); // 对pa指针来说,它的所有接口仅virtual void show(int a=145)一个而已,没有参数类型是void的版本,所以编译时只当它所调用的show是A用到缺省参数的那个版本,所以编译期静态绑定了A的缺省参数145。 运行时动态绑定类D时,发现类D没有继承参数为int的那个版本,于是只能上溯到父类C寻找带int的那个版本,找到后动态绑定(别忘了这时缺省参数已经静态绑定为145)。故答案为C: c=145小结一下上面的分析,实际上对后两个函数,我们最终使用到的是一个定义在派生类但使用了基类缺省参数的虚函数。这也就是混淆大家视线的原因所在。PS:罗罗嗦嗦写了一大堆,比较细致,只是写给自己看的,不知大家能接受吗?
更正1:上文倒数第6行,应为“发现类D没有覆盖参数为int的那个版本”。
to RookieStar(★)(巴巴罗萨) 感谢您的精辟的分析。 好象JAVA中没有这些个麻烦的问题。
请解释工作机理,好吗?
其实考的就是静态重载动态连接着两个非常关键的概念吧c++工作不用记的不是很清楚勒不懂....
void main()
{ A a,*pa=&a;
B b; C c; D d;
pa=&b; pa->show(77);//这个地方没有疑问吧
pa=&c; pa->show();//这个地方为什么默认参数的值是145而不是C::show的999呢?
//因为默认参数是一个编译期的概念,而虚函数则是运行期决定的,
//所以编译的时候传入了A::show的默认值145
pa=&d; pa->show();//此处调用的还是C::show而不是D::show,因为D::show根本就
//不是虚函数(参数类型不同)。
}
-----------------------------------------------------------其实这个问题不从语法上讲,仅仅从逻辑上来看也是应该的
现在类A提供了一个接口show(),默认的参数是145,没错吧
类A的用户按照这个接口去调用show,他不需要知道show是否被重载,他只要该调用完成show的功能,并且他知道他传入了一个参数:145(默认)。
要是这个接口被实现时,参数被偷偷换成了999,该用户岂不郁闷?
它们都是多态的形式,因为第一个pa->show(77);给重新复职了,所以是77,不过他调用的还是A的方法。
其他的父类接口覆盖了子类接口,典型多态!
难得在java版也能看见C++的题,当然要凑凑热闹了
class A{ public:
virtual void show(int a){cout<<"A: a="<<a<<endl; }
virtual void show(char *sj){cout<<"A: a=dfgdfgdfg"<<sj<<endl; }
};
class B:public A
{ public:
void show(int b){ cout<<"B: b="<<b<<endl; }
};
class C:public B
{ public:
void show(int c=999){ cout<<"C: c="<<c<<endl; }
};
class D:public C
{ public:
void show(char *sj){ cout<<"D:\ndfgdfgdfgdfg"; }
};
void main()
{ A a,*pa=&a;
B b; C c; D d;
pa=&b; pa->show(77);
pa=&c; pa->show(771);
pa=&d; pa->show("effdf");}
改一下你的程序,请大家看看输出是什么?
不会
郁闷
C:c=771
D:
dfgdfgdfgdfg
1. An object's static type is the type you declare it to have in the program text. Consider this class hierarchy
在我们这个例子里,指针pa的静态型别是A*。
2. An object's dynamic type is determined by the type of the object to which it currently refers. That is, its dynamic type indicates how it will behave.
在这个例子里,pa=&b; pa=&c; pa=&d;执行完后,代表指针pa的动态型别分别是B*,C*和D*。下面分析一下4个类中的同名函数show:
void A::show(int a=145);
void B::show(int b);
void C::show(int c=999);
void D::show();
毋庸置疑,类A是B、C、D的基类,所以A中定义的show由其声明可知是一个虚函数。
B::show和C::show由于参数数量和类型与A::show相同,故由类的公有继承可知,它们仍然是虚函数。只是此3个虚函数分别代表3个不同的版本。
D::show不同上面3个,因为其参数类型实际上是void,故它与其父类传承下来的那个虚函数show没有关系,不过是类D相对父类新增的一个show的重载版本,由于声明中没有virtual,所以,它是个非虚函数。最后明确至关重要的一点:虚函数是动态绑定(dynamically bound)而缺省参数是静态绑定(statically bound)的。
在编译期,由于静态绑定只作用于静态型别上(这点很容易理解,因为动态型别只有运行时期才知道),故在程序中凡是涉及到使用含缺省参数的函数的语句,都只能与使用该语句的对象指针的静态型别的那个版本的缺省参数绑定:在这个例子中,pa=&c; pa->show();实际上只能与A::show的缺省参数145绑定。下面,程序开始运行,我们开始分析:
pa=&b; // pa的静态型别是A*,动态型别是B*
pa->show(77); // 没有涉及到缺省参数,编译期不静态绑定。 运行时动态绑定到B::show,故答案为B: b=77pa=&c; // pa的静态型别是A*,动态型别是C*
pa->show(); // 涉及缺省参数,编译期静态绑定A::show的缺省参数145(编译器根本没看999)。 运行时动态绑定到C::show,故答案为C: c=145pa=&d; // pa的静态型别是A*,动态型别是D*
pa->show(); // 对pa指针来说,它的所有接口仅virtual void show(int a=145)一个而已,没有参数类型是void的版本,所以编译时只当它所调用的show是A用到缺省参数的那个版本,所以编译期静态绑定了A的缺省参数145。 运行时动态绑定类D时,发现类D没有继承参数为int的那个版本,于是只能上溯到父类C寻找带int的那个版本,找到后动态绑定(别忘了这时缺省参数已经静态绑定为145)。故答案为C: c=145小结一下上面的分析,实际上对后两个函数,我们最终使用到的是一个定义在派生类但使用了基类缺省参数的虚函数。这也就是混淆大家视线的原因所在。PS:罗罗嗦嗦写了一大堆,比较细致,只是写给自己看的,不知大家能接受吗?
感谢您的精辟的分析。
好象JAVA中没有这些个麻烦的问题。