笔试之编程技术

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;
  •   允许一种类型用于多个目的,同时使得每次使用该类型的目的明确。
posted @ 2015-01-28 21:49  wiessharling  阅读(178)  评论(0编辑  收藏  举报