C++面试笔记--面向对象

说到面向对象,大家第一反应应该就是它的三大特性:封装性、继承性和多态性。那么我们先简单的了解一下这三大特性:

     (1)封装性:封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

在C++中类中成员的属性有:public, protected, private,这三个属性的访问权限依次降低。

     (2)继承性:继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

     (3)多态性:多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。实现多态,有二种方式,覆盖,重载。

覆盖,是指子类重新定义父类的虚函数的做法。

重载,是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。

  • 1、C++中空类默认产生哪些类成员函数?

    答案:

    对于一个空类,编译器默认产生4个成员函数:

    (1)默认构造函数

    (2)析构函数

    (3)拷贝构造函数

    (4)赋值函数

  • 2、结构是否可以有构造函数、析构函数及成员函数?如果可以,那么结构和类还有什么区别吗?

    答案:

    区别是class中变量默认是private,struct中的变量默认是public。class继承默认是private继承,而struct继承默认是public继承。struct可以有构造函数、析构函数,之间也可以继承甚至是多重继承,等等。C++中的struct其实和class意义一样,唯一不同就是struct里面默认的访问控制是public,class中默认访问控制是private。C++中存在struct关键字的唯一意义就是为了让C程序员有个归属感,是为了让C++编译器兼容以前用C开发的项目。

    下面我们写一段struct中继承的例子。

     1 #include<iostream>
     2 using namespace std;
     3 enum Bread{Golden,Cairn,Dandie,SheTland,Lab};
     4 
     5 struct mannal{
     6 public:
     7     mannal():itsAge(2),itsWeight(5){}
     8     ~mannal(){}
     9 
    10     int getage()const {return itsAge;}
    11     void setage(int age){itsAge=age;}
    12     int getweight()const {return itsWeight;}
    13     void setweight(int weight){itsWeight=weight;}
    14 
    15     void speak()const{cout<<"mannal sound!"<<endl;}
    16     void sleep()const {cout<<"sleeping!"<<endl;}
    17 
    18 protected:
    19     int itsAge;
    20     int itsWeight;
    21 };
    22 struct dog:public mannal{
    23 private:
    24     Bread itebread;
    25 
    26 public:
    27     dog():itebread(Golden){}
    28     ~dog(){}
    29     Bread getbread()const {return itebread;}
    30     void getbread(Bread bread){itebread=bread;}
    31     void wagtail()const {cout<<"wagging!"<<endl;}
    32     void begforfood()const{cout<<"food!"<<endl;}
    33 
    34 };
    35 int main(){
    36     dog fido;
    37     fido.speak();
    38     fido.wagtail();
    39     cout<<"fiod is  "<<fido.getage()<<"years old!"<<endl;
    40     return 0;
    41 }

     

  • 3、下面程序哪个语句是错的?

    struct test{
        test(int){}
        test(){}
        void fun(){}
    };
    int main()
    {
        test a(1);//语句一
        test b();//语句二
        a.fun();//
        b.fun();////答案选四,因为test b(),这个声明了一个函数,然而本意是想创建一个对象b,但是这个声明函数的错误在编译的时候是检测不出来的,所以就调用不了fun,所以四错误。
        
    }

     

  • 4、下面程序打印出的结果是什么?
    #include<iostream>
    using namespace std;
    class base
    {
    private:
        int m_i;
        int m_j;
    public:
        base( int i ) : m_j(i),m_i(m_j) {
        base() : m_j(0),m_i(m_j){}
        int get_i() {return m_i;}
       int get_j() {return m_j;}
    };
    int main ()
    {
        base obj(98);
        cout << obj.get_i() <<endl<< obj.get_j() <<endl;
        return 0;
    }

     

    解析:本题想得到的结果是“98,98”。但是成员变量的声明是先 m_i ,然后是 m_j;初始化列表的初始化变量顺序是根据成员变量的声明顺序来执行的,因此,先初始化 m_i,但此时 m_j 还未初始化,m_i 会被赋予一个随机值。改变一下成员变量的声明顺序可以得到预想的结果。

    答案:

    输出结果第一个为随机数,第二个是98。

  • 5、析构函数可以为 virtual 型,构造函数则不能,为什么?

    答案:

    虚函数采用一种虚调用的办法。虚调用是一种可以在只有部分信息的情况下工作的机制,特别允许我们调用一个只知道接口而不知道其准确对象类型的函数。但是如果要创建一个对象,你势必要知道对象的准确类型,因此构造函数不能为 virtual。

     

    6、如果虚函数是非常有效的,我们是否可以把每个函数都声明为虚函数?

    答案:

    不行,这是因为虚函数是有代价的:由于每个虚函数的对象都必须维护一个 v 表,因此在使用虚函数的时候会产生一个系统开销。如果仅是一个很小的类,且不行派生其他类,那么根本没必要使用虚函数。

  • 6、哪一种成员变量可以在同一类的实例间共享?

    答案:

    必须使用静态成员变量在一个类的所有实例间共享数据。如果想限制对静态成员变量的访问,必须把它们声明为保护型或私有型。不允许用静态成员去存放某一个对象的数据。静态成员函数是在这个类的所有对象间共享的。如果静态成员数据设为私有的,可以通过共有静态和产能原函数访问。

  • 7、编写类 String 的构造函数、析构函数和赋值函数。

       

    #include<iostream>
    using namespace std;
    class string{
       string(const char *str);
       string(const string &);
       ~string();
       string &operator=(const string &) ;
       private:
           char *m_data;
    };
    
    string::~string(){//析构函数
        delete []m_data;
    }
    string::string(const char *str){//构造函数,利用复制操作进行。
        if(NULL==str){
            m_data=new char[1];
            *m_data='\0';
        }
        else{
            int length=strlen(str);
            m_data=new char [length+1];
            strcpy(m_data,str);
        }
    }
    string::string(const string & a){
        int lenght=strlen(a.m_data);
        m_data=new char[length+1];
        strcpy(m_data,a,m_data);
    }
    string & string::operator=(const string &a){
        if(this==&other){//检查自赋值
            return *this;
        }
        delete []m_data;//释放原有的内存资源。
        int length=strlen(a.m_data);//分配新内存资源,并复制内容
        m_data=new char[length+1];
        strcpy(m_data,a.m_data);
        return *this;
    }

     

  • 8、重载与覆盖有什么不同?

    答案:

         虚函数总是在派生类中被改写,这种改写被称为“override”(覆盖)。

         override 是指派生类重写基类的虚函数,重写的函数必须有一致的参数表和返回值。Override这个单词好像一直没什么合适的中文词汇来对应。有些人译为“覆盖”,还贴切一些。

         overload约定成俗地被翻译为“重载”,是指编写一个与自己已有函数同名但是参数表不同的函数。例如一个函数既可以接受整型数作为参数,也可以接收浮点数作为参数。重载不是一种面向对象的编程,而是一种语法规则,重载与多态没什么直接关系。

  • 9、为什么析构函数可以是virtual,但是构造函数不行呢?

    答案:

    虚函数采用的是一种虚调用的方法。虚调用是一种可以在只有部分信息的情况下工作的机制,特别允许我们调用一个只知道借口而不知道准确对象类型的函数,但是如果要创建一个对象你势必要知道对象的准确类型,因此构造函数不能为虚。

  • 10、友元函数去实现两个点之间的距离,写一个poiny类

    答案:

     1 #include<iostream>
     2 using namespace std;
     3 class point{
     4 private:
     5     double x,y;
     6 public:
     7     point(double a=0.0,double b=0.0):x(a,b){}
     8     friend double distance(point &left,point &right){}
     9 };
    10 double distance(point &left,point &right){
    11     return ((left.x-right.x)^2+(left.y-right.y)^2)^0.5;
    12 }

     

  • 11、最好不要从析构函数中抛出异常!!!,构造函数中可以抛出异常,虚方法中也是可以抛出异常的。

    答案:

     

转载于:https://www.cnblogs.com/Kobe10/p/5562936.html

面向对象程序设计》试题 一、单选题(每空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、付费专栏及课程。

余额充值