C++ 面试题(面向对象篇)

面向对象


前言

提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


1、什么是多态?

多态就是多种形态。相同的方法调用,不同的实现方式,即”一个接口,多种方法“。
就是用同样的接口访问功能不同的函数.在C++中主要分为静态多态和动态多态两种。其中,静态多态就是在程序运行前由编译器在编译期间完成的,主要通过函数重载和模板实现;动态多态就是在程序运行时根据实际类型调用相应的方法,主要通过虚函数实现.
注:引出函数重载和虚函数

2、什么是函数重载?有什么用?有什么好处?

在同一作用域内,可以有一组具有相同名字,不同参数列表(参数个数,参数类型,顺序)的函数,这组函数被称为函数重载.

常用来处理实现功能类似,数据类型不同的问题.
避免名字空间的污染,对于程序的可读性有很大的好处.

3、函数重载和重写的区别

定义不同:重载函数的参数类型,参数顺序和个数不同;重写的参数类型和返回值完全相同

范围不同:重载发生在一个类中;重写发生在继承类中.

4、为什么不能根据返回类型不同来重载

因为调用时不能指定类型信息,编译器不知道调用哪个函数。
函数返回值只是作为函数运行之后的一个”状态“,他是保持方法的调用者与被调用者进行通信的关键,并不能作为某个方法的”标识“。

5、运行期多态的实现原理

运行时多态通过虚函数和虚函数表实现.一个含有虚函数的类中至少都有一个虚函数表指针,且有一个虚表虚函数指针指向这个虚函数表.

6、虚函数的调用过程

通过对象内存中的虚函数指针vptr找到虚函数表vtbl,再通过vtbl中的函数指针找到对应虚函数的实现区域并进行调用。所以,虚函数的调用不由指针的类型决定,而由虚函数指针指向的位置决定。

7、继承下的构造函数和析构函数执行顺序

构造:先调用父类的构造函数、再调用成员变量的构造函数、最后调用类自身的构造函数
析构:先调用类自身类的构造函数、再调用成员变量的构造函数、最后父类的构造函数

8、构造函数和析构函数能否为虚函数?

构造函数不能为虚函数;析构函数可以为虚函数.

为什么构造函数不能为虚函数?
因为编译器会为每个含有虚函数的类创建一个虚函数表,在创建对象的时候会创建一个虚函数表指针指向虚函数表.如果构造函数为虚函数,则需要用对象来调用构造函数,构造函数之前对象还不存在,因此,构造函数不能为虚函数.

虚函数表为编译期创建,对象为运行时创建,虚函数指针也是运行时创建的,

为什么析构函数可以为虚函数?
当基类的对象的指针指向派生类对象,若析构函数不为虚函数,delete基类对象的时候,只会调用基类的析构函数,不会调用派生类的析构函数,这样会造成内存泄露.(若析构函数是虚函数,则会先调用派生类的析构函数然后再调用基类的析构函数)

9、虚函数表和虚函数表指针(vptr)的创建时机?

编译期确定.
虚函数表是用来存放一个类中虚函数地址的表.
编译期编译器就为每个类确定好了对应的虚函数表里的内容.所以,再程序运行时,编译器会把虚函数表的首地址赋值给虚函数表指针,所以,这个虚函数表指针就有值了.
运行时创建.
因为虚函数表指针跟着对象走,对象什么时候创建,vptr就什么时候创建.

10、虚析构函数的作用

基类采用虚析构函数会防止内存泄露。
当基类的对象的指针指向派生类对象,若析构函数不为虚函数,delete基类对象的时候,只会调用基类的析构函数,不会调用派生类的析构函数,这样会造成内存泄露.

11、空类默认产生哪些类成员函数

主要有四种:默认构造函数、拷贝构造函数、默认赋值函数、析构函数和两个取值运算符(一个带const,一个不带)

12、一个空类会占多大的空间

1字节。

13、一个类中有一个或多个虚函数会占用多大的类空间

当有虚拟成员函数时,一个或多个都是仅增加4字节。

14、什么时候必须重写拷贝构造函数

包含动态成员或包含指针成员的类都应该提供拷贝构造函数;在提供拷贝构造函数的同时,还应该考虑重载=赋值操作符
一般三种情况我们可能需要拷贝构造函数:
一个对象作为函数参数,以值传递的方式传入函数体;
一个对象作为函数返回值,以值传递的方式从函数返回;
一个对象用于给另一个对象进行初始化。

15、深拷贝和浅拷贝

在对象拷贝拷贝过程中,如果没有自定义拷贝构造函数,系统会提供一个缺省的拷贝构造函数,缺省的拷贝构造函数对于基本类型的成员变量,按字节赋值(位拷贝。也叫浅拷贝),对于类类型成员变量,调用其相应类型的拷贝构造函数。

深拷贝:每个对象共同拥有自己的资源,必须显式提供拷贝构造函数和赋值运算符;
浅拷贝:也叫位拷贝,拷贝构造函数,赋值重载多个对象共用同一块资源,同一块资源释放多次,崩溃或者内存泄露。


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

面向对象程序设计》试题 一、单选题(每空2分,共40分) 1、关于C++与C语言关系的描述中,( )是错误的。 A.C语言C++语言的一个子集 B.C语言C++语言是兼容的 C.C++语言对C语言进行了一些改进 D.C++语言和C语言都是面向对象的 2、已知:int m=10; 下列表示引用的方法中,( )是正确的。 A.int& x=m; B.int& y=10; C.int& z; D.float& t=&m; 3、考虑下面的函数原型声明: void DefPar(int a, int b=7, char z = '*'); 下面函数调用中,不合法的是( )。 A.DefPar(5); B.DefPar(5,8); C.DefPar(5,'#'); D.DefPar(0,0,'*'); 4、系统在调用重载函数时往往根据一些条件确定哪个重载函数被调用,在下列选项中,不能作为依据的是( )。 A.函数的返回值类型 B.参数的类型 C.函数名称 D.参数个数 5、下列有关C++类的说法中,不正确的是( )。 A.类是一种用户自定义的数据类型 B.只有类中的成员函数或类的友元函数才能存取类中的私有成员 C.在类中,如果不做特别说明,所有成员的访问权限均为私有的 D.在类中,如果不做特别说明,所有成员的访问权限均为公用的 6、已知X类,则当程序执行到语句X array[3];时,调用了( )次构造函数。 A.0 B.1 C.2 D.3 7、有关析构函数的说法,不正确的是( )。 A.析构函数有且仅有一个 B.析构函数和构造函数一样可以有形参 C.析构函数的功能是在系统释放对象之前作一些内存清理工作 D.析构函数无任何函数类型 8、类定义的内容允许被其对象无限制地存取的是( )。 A.private 部分 B. protected 部分 C.public 部分 D.以上都不对 9、关于常数据成员的说法,不正确的是( )。 A.常数据成员的定义形式与一般常变量的,只不过常数据成员的定义必须出现在类体中 B.常数据成员必须进行初始化,并且不能被更新 C.常数据成员通过构造函数的成员初始化列表进行初始化 D.常数据成员可以在定义时直接初始化 10、运用运算符delete删除一个动态对象时( )。 A.系统首先为该动态对象调用构造函数,再释放其占用的内存 B.系统首先释放该动态对象占用的内存,再为其调用构造函数 C.系统首先为该动态对象调用析构函数,再释放其占用的内存 D.系统首先释放动态对象占用的内存,再为其调用析构函数 11、可在类外用p.a的形式访问派生类对象 p的基类成员a,其中a是( )。 A.私有继承的公用成员 B.公用继承的私有成员 C.公用继承的保护成员 D.公用继承的公用成员 12、在公用继承方式下,有关派生类对象和基类对象的关系,不正确的叙述是(  )。 A.派生类的对象可以赋给基类的对象 B.派生类的对象可以初始化基类的引用 C.派生类的对象可以直接访问基类中的成员 D.派生类的对象的地址可以赋给指向基类的指针 13、设置虚基类的目的是( )。 A.简化程序 B.消除二义性 C.提高运行效率 D.减少目标代码 14、在C++中,用于实现动态多态性的是( )。 A.内联函数 B.重载函数 C.模板函数 D.虚函数 15、不能说明为虚函数的是( )。 A.析构函数 B.构造函数 C.类的成员函数 D.以上都不对 16、如果一个类至少有一个纯虚函数,那么就称该类为( )。 A.抽象类 B.派生类 C.纯基类 D.以上都不对 17、下面关于友元的描述中,错误的是( )。 A.友元函数可以访问该类的私有数据成员 B.一个类的友元类中的成员函数都是这个类的友元函数 C.友元可以提高程序的运行效率 D.类与类之间的友元关系可以继承 18、下列运算符中,( )运算符在C++中不能被重载。 A.&& B.[ ] C.:: D.new 19、模板的使用实际上是将类模板实例化成一个( )。 A.函数 B.对象 C.类 D.抽象类 20、假定MyClass为一个类,则该类的拷贝构造函数的声明语句为( )。 A.MyClass(MyClass x) B.MyClass&(MyClass x) C.MyClass(MyClass &x) D.MyClass(MyClass *x) 二、填空题(前16个空,每空1分,后2个空,每空2分,共20分) 1、类和对象的关系可表述为:类是对象的 ,而对象则是类的 。 2、在C++中,三种继承方式的说明符号为 、 和 ,如果不加说明,则默认的继承方式为 。 3、如果只想保留公共基类的一个复制,就必须使用关键字 把这个公共基类声明为虚基类。 4、若要把void fun( )定义为类A的友元函数,则应在类A的定义中加入语句 。 5、类的静态成员分为 和 。 6、运算符重载要求保持其原来的操作数个数、 、 和语法结构。 7、通过关键字 可以声明模板,通过关键字 指定函数模板的类型参数,有几个类型参数就有几个类型关键字。 8、列出C++中两种用户自定义的数据类型: 、 。 9、构造函数的作用是 。 10、后置自增运算符“++”重载为类的成员函数(设类名为A)的形式为 。 三、阅读下面3个程序,写出程序运行时输出的结果:(共13分) 1、#include <iostream> using namespace std; void fun(int &a,int &b) { int p; p=a; a=b; b=p; } void exchange(int &a,int &b,int &c) { if(a<b) fun(a,b); if(a<c) fun(a,c); if(b<c) fun(b,c); } void main() { int a=12,b=89,c=56; exchange(a,b,c); cout<<"a="<<a<<",b="<<b<< ",c="<<c<<endl; } 2、#include <iostream> using namespace std; class Date { public: Date(int,int,int); Date(int,int); Date(int); Date(); void display(); private: int month, day, year; }; Date::Date(int m, int d, int y) : month(m),day(d),year(y) { } Date::Date(int m,int d):month(m),day(d) { year=2009; } Date::Date(int m) : month(m) { day=1; year=2010; } Date::Date() { month=1; day=1; year=2010; } void Date::display() { cout <<month<<"/"<<day<<"/"<<year<<endl; } void main() { Date d1(12,31,2009); Date d2(12,31); Date d3(1); Date d4; d1.display(); d2.display(); d3.display(); d4.display(); } 3、#include <iostream> using namespace std; class A { public: A() { cout<<"constructing A "<<endl; } ~A() { cout<<"destructing A "<<endl; } }; class B: public A { public: B() { cout<<"constructing B "<<endl; } ~B() { cout<<"destructing B "<<endl; } }; class C : public B { public: C() { cout<<"constructing C "<<endl; } ~C() { cout<<"destructing C "<<endl; } }; void main() { C c1; } 四、编程题(共27分) 1、(10分)已知复数类Complex的声明如下: class Complex { public: Complex(); Complex(double); Complex(double, double); friend Complex operator + (Complex&, Complex&); friend ostream & operator << (ostream&, Complex&); friend istream& operator >> (istream&, Complex&); private: double real, imag; }; 要求: (1)写出该类的所有构造函数的类外定义代码。 (2)写出对运算符“+”、“<<”、“>>”进行重载的运算符重载函数的定义。 2、(17分)下列Base类是一个表示形状的抽象类,area( )为求图形面积的函数,total( )则是一个通用的用以求不同形状的图形面积总和的函数。 class Base { public: virtual double area()=0; }; double total(Base *s[ ], int n) { double sum=0.0; for(int i=0; i<n; i++) sum+=s[i]->area( ); return sum; } 要求: (1)从Base类派生圆类(Circle)、正方形类(Square),圆类新增数据成员半径(radius),正方形类新增数据成员边长(a),圆类和正方形类都有构造函数,修改、显示数据成员值的函数,求面积函数。 (2)写出main( )函数,计算半径为5.5的圆和边长为9.9的正方形的面积和(必须通过调用total函数计算)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值