zoukankan      html  css  js  c++  java
  • 笔试之编程技术

    1. 面向对象的三个特征

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

      继承:继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。通过继承创建的新类称为“子类”或“派生类”。被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。

      多态:是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。实现多态,有二种方式,覆盖,重载。覆盖,是指子类重新定义父类的虚函数的做法。重载,是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。

    2. static_cast、dynamic_cast、reintepret_cast、cont_cast有什么不同?为什么需要多种不同的转换风格?

      在看这些转换之前先来了解一下C风格的转换:

      隐式转换:

    short a = 2000;
    int b;
    b = a;        //隐式转换

      显式转换:

    double a = 2000.3;
    short b;
    b = (short) a;    // c-like cast notation
    b = short(a);    // functional notation 

      这种显式转换方式简单直观,但并不安全!

      ok,下面我们来看看上述的各种转换方式:

      1)static_cast             静态转换    用法:static_cast<type_id> (expression)

      静态转换是最接近于C风格转换,很多时候都需要程序员自身去判断转换是否安全。但其实 static_cast 已经有安全性的考虑了,比如对于不相关类指针之间的转换。

      下面对比一下C风格转换与static_cast转换

    // class type-casting
    #include <iostream>
    using namespace std;
    
    class CDummy {
        float i,j;
    public:
        CDummy(float x, float y)
        {
            i = x;
            j = y;
        }
    };
    
    class CAddition {
        int x,y;
      public:
        CAddition (int a, int b) { x=a; y=b; }
        int result() { return x+y;}
    };
    
    int main () 
    {
      CDummy d(5, 10);
      CAddition *padd;
      padd = (CAddition*) &d;
      cout << padd->result()<<endl;
      return 0;
    }

      此时,两个不相关的类指针之间的转换是成功的,编译器也没有提示Warning!但是,在 static_cast 是不允许转换的,因此可以看出 static_cast 有自身的安全机制!

        padd = static_cast<CAddition*>(&d);
    error: invalid static_cast from type ‘CDummy*’ to type ‘CAddition*’

        总结一下:static_cast最接近于C风格转换了,但在无关类的类指针之间转换上,有安全性的提升。

    该运算符把 expression 转换为 type-id 类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:
    ①用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。
    进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;
    进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
    ②用于基本数据类型之间的转换,如把 int 转换成 char,把 int 转换成 enum。这种转换的安全性也要开发人员来保证。
    ③把空指针转换成目标类型的空指针。
    ④把任何类型的表达式转换成 void 类型。
    注意:static_cast 不能转换掉 expression 的 const、volatile、或者__unaligned属性。

      2)dynamic_cast        动态转换    用法:dynamic_cast<type_id> (expression)

      dynamic_cast 运算符可以在执行期决定真正的类型。如果 downcast 是安全的(也就说,如果基类指针或者引用确实指向一个派生类对象)这个运算符会传回适当转型过的指针。

      如果 downcast 不安全,这个运算符会传回空指针(也就是说,基类指针或者引用没有指向一个派生类对象)。
      dynamic_cast 主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
      在类层次间进行上行转换时,dynamic_cast 和 static_cast 的效果是一样的;
      在进行下行转换时,dynamic_cast 具有类型检查的功能,比 static_cast 更安全。

      3)reintepret_cast    强制类型转换符     用法:reinterpret_cast<type-id> (expression)

      这和 C 的显式转换有点类似,例如,对于两个毫无相关的类之间的转换也是成功的!

    class CDummy {
        float i,j;
    public:
        CDummy(float x, float y)
        {
            i = x;
            j = y;
        }
    };
    
    class CAddition {
        int x,y;
      public:
        CAddition (int a, int b) { x=a; y=b; }
        int result() { return x+y;}
    };
    
    int main () 
    {
        CDummy d(5, 10);
        CAddition *padd;
        //padd = static_cast<CAddition*>(&d);
        padd = reinterpret_cast<CAddition*>(&d);
        cout << padd->result()<<endl;
    
        //int pointer to int
        int *i = new int(100);
        int y = reinterpret_cast<int>(i);
        cout<<"y = "<<y<<endl;
    
        //int to int pointer
        int *c = NULL;
        c = reinterpret_cast<int*>(y);
        cout<<"*d = "<<*c<<endl;  //equal to *i
        return 0;
    }

      结果输出:

    $ ./cast 
    -2118123520
    y = 161939464
    *d = 100

      总结:reinterpret_cast 是为了映射到一个完全不同类型的意思,这个关键词在我们需要把类型映射回原有类型时用到它。我们映射到的类型仅仅是为了故弄玄虚和其他目的,这是所有映射中最危险的。(这句话是C++编程思想中的原话)

      static_cast 和 reinterpret_cast 的区别主要在于多重继承,比如

    class A {
        public:
        int m_a;
    };
     
    class B {
        public:
        int m_b;
    };
     
    class C : public A, public B {};
    C c;
    printf("%p, %p, %p", &c, reinterpret_cast<B*>(&c), static_cast <B*>(&c));


      前两个的输出值是相同的,最后一个则会在原基础上偏移4个字节,这是因为 static_cast 计算了父子类指针转换的偏移量,并将之转换到正确的地址(c里面有m_a,m_b,转换为B*指针后指到m_b处),而reinterpret_cast却不会做这一层转换。
      因此, 你需要谨慎使用 reinterpret_cast.

      总结:

      1. static_cast
    对于内建类型的转换
        会出现溢出情况,需要程序员自身去判断转换是否安全
    对于单继承的转换
        class A{}; class B: public A {};
        B=>A   允许        没有类型检查
        A=>B   不允许
    对于多继承的转换
        class A{}; class B{}; class C: public A, public B {};
        A=>C  不允许
        B=>C  不允许
        C=>A  允许
        C=>B  允许
    对于无相关类之间的转换
        class A{}; class B{};
        A=>B 不允许
        B=>A 不允许
    是否能够改变被转换者的const volatile __unaligned属性
        不能
        
    2. dynamic_cast
    对于内建类型的转换
        int a = dynamic_cast<int>(double d);  //ERROR
        double d = dynamic_cast<double>(int i); //ERROR
    对于单继承的转换
        class A{}; class B: public A {};
        B=>A   允许          在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
        A=>B   不允许
    对于多继承的转换
        class A{}; class B{}; class C: public A, public B {};
        A=>C  不允许
        B=>C  不允许
        C=>A  允许
        C=>B  允许
    对于无相关类之间的转换
        class A{}; class B{};
        A=>B 不允许
        B=>A 不允许
    是否能够改变被转换者的const volatile __unaligned属性
        不能

    3. reinterpret_cast
    对于内建类型的转换
        int a = reinterpret_cast<int>(double d);  //ERROR
        double d = reinterpret_cast<double>(int i); //ERROR
    对于单继承的转换
        class A{}; class B: public A {};
        B=>A   
        A=>B   
    对于多继承的转换
        class A{}; class B{}; class C: public A, public B {};
        A=>C  
        B=>C  
        C=>A  
        C=>B  
    对于无相关类之间的转换
        class A{}; class B{};
        A=>B 允许   这是需要注意的。
        B=>A 允许   这是需要注意的。
    是否能够改变被转换者的const volatile __unaligned属性
        不能
    4. const_cast

    C风格转换是“万能的转换”,但需要程序员把握转换的安全性,编译器无能为力;static_cast最接近于C风格转换,但在无关类指针转换时,编译器会报错,提升了安全性;dynamic_cast要求转换类型必须是指针或引用,且在下行转换时要求基类是多态的,如果发现下行转换不安全,dynamic_cast返回一个null指针,dynamic_cast总是认为void*之间的转换是安全的;reinterpret_cast可以对无关类指针进行转换,甚至可以直接将整型值转成指针,这种转换是底层的,有较强的平台依赖性,可移植性差;const_cast可以将常量转成非常量,但不会破坏原常量的const属性,只是返回一个去掉const的变量。

    五. typedef 的作用

      typedef通常被用于以下三种目的:

    •   为了隐藏特定类型的实现,强调使用类型的目的;
    •   简化复杂的类型定义,使其更易于理解;typedef QList<EntityCustomer> CustomerLst;
    •   允许一种类型用于多个目的,同时使得每次使用该类型的目的明确。
  • 相关阅读:
    ZOJ 2588 Burning Bridges
    POJ 1966 ZOJ 2182 Cable TV Network
    HDU 5348 MZL's endless loop
    HDU 5352 MZL's City
    Tarjan算法求解无向连通图的割点、割边、点双连通分量和边双连通分量的模板
    ZOJ 1119 SPF
    HDU 3452 Bonsai
    HDU 1520 Anniversary party
    POJ 2239 Selecting Courses
    POJ 1144 Network
  • 原文地址:https://www.cnblogs.com/wiessharling/p/4257201.html
Copyright © 2011-2022 走看看