C++函数中那些不可以被声明为虚函数的函数
习题9及其解答

习题9及其解答9.1 选择题1.在C++中,要实现动态联编,必须使用( d )调用虚函数。
(a) 类名(b) 派生类指针(c) 对象名(d) 基类指针2.下列函数中,不能说明为虚函数的是( c )。
(a) 私有成员函数(b) 公有成员函数(c) 构造函数(d) 析构函数3.在派生类中,重载一个虚函数时,要求函数名、参数的个数、参数的类型、参数的顺序和函数的返回值( a )。
(a) 相同(b) 不同(c) 相容(d) 部分相同4.C++中,根据( d )识别类层次中不同类定义的虚函数版本。
(a) 参数个数(b) 参数类型(c) 函数名(d) this指针类型5.虚析构函数的作用是( c )。
(a) 虚基类必须定义虚析构函数(b) 类对象作用域结束时释放资源(c) delete动态对象时释放资源(d) 无意义6.下面函数原型中,( b )声明了fun为纯虚函数。
(a) void fun()=0; (b) virtual void fun()=0;(c) virtual void fun(); (d) virtual void fun(){ };7.若一个类中含有纯虚函数,则该类称为( c )。
(a) 基类(b) 纯基类(c) 抽象类(d) 派生类8.假设 Aclass为抽象类,下列正确的说明语句是( b )。
(a) Aclass fun( int ) ; (b) Aclass * p ;(c) int fun( Aclass ) ; (d) Aclass Obj ;9.下面描述中,正确的是( d )。
(a) 虚函数是没有实现的函数(b) 纯虚函数是返回值等于0的函数(c) 抽象类是只有纯虚函数的类(d) 抽象类指针可以指向不同的派生类10.构造异质链表的意义是( d )。
(a) 用数组组织类对象(b) 用链表组织类对象(c) 用抽象类指针指向派生类对象(d) 用抽象类指针构造派生类对象链表9.2阅读下列程序,写出执行结果1.#include <iostream>using namespace std;class Bclass{ public:Bclass( int i, int j ) { x = i; y = j; }virtual int fun() { return 0 ; }protected:int x, y ;};class Iclass:public Bclass{ public :Iclass(int i, int j, int k):Bclass(i, j) { z = k; }int fun() { return ( x + y + z ) / 3; }private :int z ;};int main(){ Iclass obj( 2, 4, 10 );Bclass p1 = obj;cout << p1.fun() << endl;Bclass &p2 = obj ;cout << p2.fun() << endl;cout << p2.Bclass :: fun() << endl;Bclass *p3 = &obj;cout << p3 -> fun() << endl;}【解答】552.#include <iostream>using namespace std;class Base{ public:virtual void getxy( int i,int j = 0 ) { x = i; y = j; } virtual void fun() = 0 ;protected:int x , y;} ;class A : public Base{ public:void fun(){ cout<<"x = "<<x<<'\t'<<"y = x * x = "<<x*x<<endl; }};class B : public Base{ public:void fun(){ cout << "x = " << x << '\t' << "y = " << y << endl;cout << "y = x / y = " << x / y << endl;}} ;int main(){ Base * pb;A obj1;B obj2;pb = &obj1;pb -> getxy( 10 );pb -> fun();pb = &obj2;pb -> getxy( 100, 20 );pb -> fun();}【解答】x = 10 y = x*x = 100x = 100 y = 20y = x / y = 59.3 思考题1.在C++中,使用类体系依靠什么机制实现程序运行时的多态?【解答】在C++中,基类指针可以指向派生类对象,以及基类中拥有虚函数,是支持多态性的前提。
C语言笔试题大全

答:可以,在不同的C文件中以static形式来声明同名全局变量。
可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错
4、语句for(;1;)有什么问题?它是什么意思?
答:和while(1)相同。
char* dest = (char*)malloc(len+1);//要为\0分配一个空间
char* d = dest;
char* s = &src[len-1];//指向最后一个字符
while( len-- != 0 )
*d++=*s--;
*d = 0;//尾部要加\0
printf("%s\n",dest);
static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用;
static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;
static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
{
t=str[i];
str[i]=str[len-i-1]; str[len-i-1]=t;
}
printf("%s",str);
return 0;
}
1.-1,2,7,28,,126请问28和126中间那个数是什么?为什么?
第一题的答案应该是4^3-1=63
规律是n^3-1(当n为偶数0,2,4)
n^3+1(当n为奇数1,3,5)
11.堆栈溢出一般是由什么原因导致的?
C++笔记之虚函数

虚函数:为了重载和多态的需要,在基类中是由定义的,即便定义是空,所以子类中可以重写也可以不写基类中的函数!纯虚函数在基类中是没有定义的,必须在子类中加以实现,很像java中的接口函数!不能直接实例化,需要派生类来实现函数定义纯虚函数及其作用:纯虚函数是指在基类中声明但是没有定义的虚函数:virtual type func(param list) = 0;把虚函数声明为纯虚函数可以强制在派生类中重新定义虚函数,否则编译器会报错。
抽象类及其特征:如果一个类至少有一个纯虚函数,则称为抽象类。
抽象类只能用来作为其他类的基类,不能定义抽象类的对象,因为在抽象类中有一个或者多个函数没有定义。
但是能够使用抽象类来声明指针或者引用。
子类指针不能指向父类对象(即将父类对象赋值给子类指针)父类指针可以指向子类对象(即将子类对象赋值给父类指针)C++虚函数与虚函数表:多态性可分为两类:静态多态和动态多态。
函数重载和运算符重载实现的多态属于静态多态,动态多态性是通过虚函数实现的。
每个含有虚函数的类有一张虚函数表(vtbl),表中每一项是一个虚函数的地址,也就是说,虚函数表的每一项是一个虚函数的指针。
没有虚函数的C++类,是不会有虚函数表的。
两张图:一般继承(无虚函数覆盖)下面,再让我们来看看继承时的虚函数表是什么样的。
假设有如下所示的一个继承关系:请注意,在这个继承关系中,子类没有重载任何父类的函数。
那么,在派生类的实例中,其虚函数表如下所示:对于实例:Derive d; 的虚函数表如下:我们可以看到下面几点:1)虚函数按照其声明顺序放于表中。
2)父类的虚函数在子类的虚函数前面。
我相信聪明的你一定可以参考前面的那个程序,来编写一段程序来验证。
一般继承(有虚函数覆盖)覆盖父类的虚函数是很显然的事情,不然,虚函数就变得毫无意义。
下面,我们来看一下,如果子类中有虚函数重载了父类的虚函数,会是一个什么样子?假设,我们有下面这样的一个继承关系。
《C----语言程序设计》作业题..

《C++语言程序设计》作业题一、判断题()1、写在类体内的函数都是内联函数。
()2、通常的拷贝初始化构造函数的参数是某个对象的指针名。
()3、重载运算符可改变原运算符的优先级和结合性。
()4、在设置了默认参数值后,调用函数的对应实参就必须省略。
()5、析构函数是一种函数体为空的成员函数。
()6、某类的友元类的所有成员函数可以存取或修改该类中的私有成员。
()7、对象数组的元素可以是不同类的对象。
()8、函数的参数个数、类型及位置都相同,只是函数返回值类型不同,这不是重载函数。
()9、派生类是从基类派生出来的,但它不能再生成新的派生类。
()10、构造函数和析构函数都不能重载。
()11、在公有继承中,基类中只有公有成员对派生类的对象是可见的。
()12、this指针是一个指向正在被某个成员函数操作的对象的指针。
()13、一维对象指针数组的每个元素应该是某个类的对象的地址值。
()14、在C++中,定义函数时必须给出函数的类型。
()15、析构函数是一种函数参数表为空的成员函数。
()16、派生类的继承方式有两种:公有继承和私有继承。
()17、自身类对象的引用不可以作为该类的成员。
()18、多重继承情况下,派生类中对基类成员的访问不会出现二义性。
()19、可以在类的构造函数中对静态数据成员进行初始化。
()20、多重继承情况下,派生类的构造函数的执行顺序取决于定义派生类时所指定的各基类的顺序。
()21、在单继承情况下,派生类中对基类成员的访问不会出现二义性。
()22、转换函数不是成员函数,它是用来进行强制类型转换的。
()23、在公有继承中,基类中的保护成员对派生类对象是可见的。
()24、虚基类是用来解决多继承中公共基类在派生类中只产生一个基类子对象的问题。
()25、在保护继承中,基类中的公有成员对派生类对象是可见的。
()26、抽象类是指一些不能定义对象的类。
()27、虚函数是用virtual关键字说明的成员函数。
c语言最全经典面试题

第一部分:基本概念及其它问答题1、关键字static的作用是什么?这个简单的问题很少有人能回答完全。
在C语言中,关键字static有三个明显的作用:1). 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
2). 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。
它是一个本地的全局变量。
3). 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。
那就是,这个函数被限制在声明它的模块的本地范围内使用。
大多数应试者能正确回答第一部分,一部分能正确回答第二部分,同是很少的人能懂得第三部分。
这是一个应试者的严重的缺点,因为他显然不懂得本地化数据和代码范围的好处和重要性。
2、“引用”与指针的区别是什么?答、1) 引用必须被初始化,指针不必。
2) 引用初始化以后不能被改变,指针可以改变所指的对象。
3) 不存在指向空值的引用,但是存在指向空值的指针。
指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。
程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。
流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用3、.h头文件中的ifndef/define/endif 的作用?答:防止该头文件被重复引用。
4、#i nclude<file.h> 与#i nclude "file.h"的区别?答:前者是从Standard Library的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。
5、描述实时系统的基本特性答:在特定时间内完成特定的任务,实时性与可靠性。
6、全局变量和局部变量在内存中是否有区别?如果有,是什么区别?答:全局变量储存在静态数据区,局部变量在堆栈中。
C++:构造函数和析构函数能否为虚函数

C++:构造函数和析构函数能否为虚函数C++:构造函数和析构函数能否为虚函数?简单回答是:构造函数不能为虚函数,⽽析构函数可以且常常是虚函数。
(1)构造函数不能为虚函数让我们来看看⼤⽜C++之⽗ Bjarne Stroustrup 在《The C++ Programming Language》⾥是怎么说的:To construct an object, a constructor needs the exact type of the object it is to create. Consequently, a constructor cannot be virtual. Furthermore, a constructor is not quite an ordinary function, In particular, it interacts with memory management in ways ordinary member functions don't. Consequently, you cannot have a pointer to a constructor.--- From 《The C++ Progamming Language》15.6.2然⽽⼤⽜就是⼤⽜,这段话对⼀般⼈来说太难理解了。
那下⾯就试着解释⼀下为什么:这就要涉及到C++对象的构造问题了,C++对象在三个地⽅构建:1、函数堆栈;2、⾃由存储区,或称之为堆;3、静态存储区。
⽆论在那⾥构建,其过程都是两步:⾸先,分配⼀块内存;其次,调⽤构造函数。
好,问题来了,如果构造函数是虚函数,那么就需要通过vtable 来调⽤,但此时⾯对⼀块 raw memeory,到哪⾥去找 vtable 呢?毕竟,vtable 是在构造函数中才初始化的啊,⽽不是在其之前。
因此构造函数不能为虚函数。
(2)析构函数可以是虚函数,且常常如此这个就好理解了,因为此时 vtable 已经初始化了;况且我们通常通过基类的指针来销毁对象,如果析构函数不为虚的话,就不能正确识别对象类型,从⽽不能正确销毁对象。
C++虚函数注意事项

C++虚函数注意事项⽬录⼀、虚函数注意事项1.构造函数2.析构函数3.友元4.没有重新定义5.重新定义将隐藏⽅法⽂章转⾃公众号:Coder梁(ID:Coder_LT)⼀、虚函数注意事项在之前的当中,我们已经讨论了虚函数的使⽤⽅法,也对它的原理进⾏了简单的介绍。
这⾥简单做⼀个总结:在基类的⽅法声明中使⽤关键字virtual可以声明虚函数加上了virtual关键字的函数在基类以及派⽣类和派⽣类再派⽣出来的类中都是虚的在调⽤虚函数时,程序将会根据对象的类型执⾏对应的⽅法⽽⾮引⽤或指针的类型在定义基类时,需要将要在派⽣类中重新定义的类⽅法声明为虚,如析构函数除了这些之外,我们还有⼀些其他需要注意的事项。
1.构造函数构造函数不能是虚函数,创建派⽣类对象时将调⽤派⽣类的构造函数,⽽⾮基类的构造函数,毕竟构造函数是根据类名调⽤的。
⼀般我们会在派⽣类中调⽤基类的构造函数,这其实不是继承机制,所以将类构造函数声明为虚没有意义。
2.析构函数前⽂说过析构函数应该是虚函数,除⾮类不被继承。
因为派⽣类当中往往含有独有的成员变量,如果析构函数⾮虚,那么会导致在对象析构时仅调⽤基类的析构函数,从⽽导致独有的成员变量内存不被释放,引起内存泄漏。
所以通常我们会将析构函数设置成virtual,即使不⽤做基类也不会引起错误,⾄多只会影响⼀点效率。
但在⼤型合作开发的项⽬当中,许多组件和类都是共享的,我们往往⽆法保证我们开发的类是否会被其他开发者继承,因此设置虚析构函数也是⼀种常规做法。
3.友元友元函数不能是虚函数,因为友元不是类成员,只有成员函数才能是虚函数。
如果我们希望友元函数也能实现类似虚函数的功能,我们可以在友元函数当中使⽤虚函数来解决。
4.没有重新定义如果派⽣类当中没有重新定义虚函数,那么将使⽤该函数的基类版本。
如果派⽣类位于派⽣链中,如B继承了A,C继承了B这种情况,那么派⽣类将会使⽤最新的虚函数版本。
5.重新定义将隐藏⽅法我们来看⼀个例⼦:class Mammal {private:string name;public:Mammal(string n): name(n) {}virtual void speak() const {cout << "can't say anything" << endl;}};class Human : public Mammal{private:string job;public:Human(string n, string j): Mammal(n), job(j) {}virtual void speak(const string st) const {cout << "i'm human" << endl;}};我们在⽗类当中定义了⼀个⽆参虚函数speak,⽽在⼦类Human当中也定义了⼀个需要传⼊⼀个string类型的虚函数speak。
C#中虚方法,抽象方法和隐藏方法

C#中虚⽅法,抽象⽅法和隐藏⽅法虚⽅法:即为基类中定义的允许在派⽣类中重写的⽅法,使⽤virtual关键字定义。
如:public virtual void EatFood(){Console.WriteLine("Animal吃东西");}注意:虚⽅法也可以被直接调⽤。
如:Animal a = new Animal();a.EatFood();执⾏输出结果为:Animal吃东西抽象⽅法:在基类中定义的并且必须在派⽣类中重写的⽅法,使⽤ abstract 关键字定义。
如:public abstract class Biology{public abstract void Live();}public class Animal : Biology{public override void Live(){Console.WriteLine("Animal重写的抽象⽅法");//throw new NotImplementedException();}}注意:抽象⽅法只能在抽象类中定义,如果不在抽象类中定义,则会报出如下错误:虚⽅法和抽象⽅法的区别1.虚⽅法必须有实现部分,抽象⽅法没有提供实现部分,抽象⽅法是⼀种强制派⽣类覆盖的⽅法,否则派⽣类将不能被实例化。
2.抽象⽅法只能在抽象类中声明,虚⽅法不是。
如果类包含抽象⽅法,那么该类也是抽象的,也必须声明类是抽象的。
3.抽象⽅法必须在派⽣类中重写,这⼀点和接⼝类似,虚⽅法不需要再派⽣类中重写。
简单说,抽象⽅法是需要⼦类去实现的。
虚⽅法是已经实现了的,可以被⼦类覆盖,也可以不覆盖,取决于需求。
抽象⽅法和虚⽅法都可以供派⽣类重写。
虚⽅法的调⽤:调⽤上,使⽤⼦类构造的对象调⽤虚⽅法,就会调⽤⼦类的⽅法,使⽤⽗类构造的对象,就会调⽤⽗类的⽅法。
隐藏⽅法的调⽤:调⽤上,使⽤⼦类类型的声明调⽤隐藏⽅法,就会调⽤到⼦类的⽅法。
若想调⽤被隐藏的⽅法,需要⽤⽗类类型的声明来调⽤。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
常见的不不能声明为虚函数的有:普通函数(非成员函数);静态成员函数;内联成员函数;构造函数;友元函数。
1、为什么C++不支持普通函数为虚函数?
普通函数(非成员函数)只能被overload,不能被override,声明为虚函数也没有什么意思,因此编译器会在编译时邦定函数。
2、为什么C++不支持构造函数为虚函数?
这个原因很简单,主要是从语义上考虑,所以不支持。
因为构造函数本来就是为了明确初始化对象成员才产生的,然而virtual function主要是为了再不完全了解细节的情况下也能正确处理对象。
另外,virtual函数是在不同类型的对象产生不同的动作,现在对象还没有产生,如何使用virtual函数来完成你想完成的动作。
(这不就是典型的悖论)
3、为什么C++不支持内联成员函数为虚函数?
其实很简单,那内联函数就是为了在代码中直接展开,减少函数调用花费的代价,虚函数是为了在继承后对象能够准确的执行自己的动作,这是不可能统一的。
(再说了,inline函数在编译时被展开,虚函数在运行时才能动态的邦定函数)
4、为什么C++不支持静态成员函数为虚函数?
这也很简单,静态成员函数对于每个类来说只有一份代码,所有的对象都共享这一份代码,他也没有要动态邦定的必要性。
5、为什么C++不支持友元函数为虚函数?
因为C++不支持友元函数的继承,对于没有继承特性的函数没有虚函数的说法。
*********************************************************************
1、顶层函数:多态的运行期行为体现在虚函数上,虚函数通过继承方式来体现出多态作用,顶层函数不属于成员函数,是不能被继承的。
2、构造函数:(1)构造函数不能被继承,因而不能声明为virtual函数。
(2)构造函数一般是用来初始化对象,只有在一个对象生成之后,才能发挥多态的作用,如果将构造函数声明为virtual函数,则表现为在对象还没有生成的情况下就使用了多态机制,因而是行不通的,如下例:
#include <iostream>
using namespace std;
class B
{
public:
B() {}
virtual void show()
{
cout<<"***"<<endl;
}
};
class D:public B
{
public:
D() {}
void show()
{
cout<<"==="<<endl;
}
};
int main(void)
{
B *pb;
D d; //先生成对象
pb=&d;
pb->show(); //再体现多态
pb=new D(); //先调用构造函数
pb->show(); //再多态
delete pb;
return 0;
}
3、static函数:不能被继承,只属于该类。
4、友元函数:友元函数不属于类的成员函数,不能被继承。
5、inline函数:inline函数和virtual函数有着本质的区别,inline函数是在程序被编译时就展开,在函数调用处用整个函数体去替换,而virtual函数是在运行期才能够确定如何去调用的,因而
inline函数体现的是一种编译期机制,virtual函数体现的是一种运行期机制。
此外,一切virtual 函数都不可能是inline函数。