C++中的抽象类及动态类型转换

抽象类与纯虚函数

1. 抽象类

类太抽象以至于无法实例化就叫做抽象类(描述是不是绝了,类越往下派生肯定越具体,越往上肯定越抽象)

2. 抽象函数/纯虚函数

2.1. 成员函数应出现在哪个继承层次?

问题:Shape类层次中,getArea()函数放在哪个层次

选择1:放哪儿都行:Shape中或子类中定义getArea()

选择2:强制要求Shape子类必须实现getArea()

2.2. 抽象函数(abstract functions)要求子类实现它

virtual double getArea() = 0;  // 在Shape类中

Circle子类必须实现getArea()纯虚函数才能实例化 

2.3. 包含抽象函数的类被称为抽象类

抽象类不能实例化(创建对象)

3. Abstract Class Example

 

C++中的抽象类及动态类型转换_第1张图片


动态类型转换 

1. 为何需要动态类型转换 

void printObject(Shape& shape)

// shape是派生类对象的引用

{

  cout << "The area is "

       << shape.getArea() << endl;

  // 如果shape是Circle对象,就输出半径

  // 如果shape是Rectangle对象,就输出宽高

}

 

 C++中的抽象类及动态类型转换_第2张图片

如果你要修改函数,让它显示圆的半径该怎么办?

2. Dynamic Casting Example

2.1. dynamic_cast 运算符

(1)     沿继承层级向上、向下及侧向转换到类的指针和引用

(2)     转指针:失败返回nullptr

(3)     转引用:失败抛异常

2.2. 例子

先将Shape对象用dynamic_cast转换为派生类Circle对象

然后调用派生类中独有的函数 

// A function for displaying a Shape object

void printObject(Shape &shape)

{

  cout << "The area is "

       << shape.getArea() << endl;

  Shape *p = &shape;

  Circle *c = dynamic_cast(p);

  // Circle& c = dynamic_cast(shape); 

  // 引用转换失败则抛出一个异常 std::bad_cast

  if (c != nullptr) // 转换失败则指针为空

  {

    cout << "The radius is "

         << p1->getRadius() << endl;

    cout << "The diameter is "

         << p1->getDiameter() << endl;

  }

}

 


向上转换和向下转换

1. 向上/向下 转型

1.1. upcasting : 将派生类类型指针赋值给基类类型指针

1.2. downcasting : 将基类类型指针赋值给派生类类型指针

 C++中的抽象类及动态类型转换_第3张图片

 

Upcast

Downcast

computer = pc

pc = computer

computer = desktop

desktop = computer

pc = desktop

desktop = pc

2. 向上/向下 转型 

2.1. 上转可不使用dynamic_cast而隐式转换

Shape* s = nullptr;

Circle *c = new Circle(2);

s = c; //OK,隐式上转

 

2.2. Downcasting must be performed explicitly. (下转必须显式执行)

Shape* s = new Circle(1);

Circle *c = nullptr;

c = dynamic_cast  (s); //显式下转

 

父上,子下

上转隐,下转显

3. 基类对象和派生类对象的互操作

3.1. 对象内存布局

Shape S;//基类对象

Circle C;//派生类对象

 

 

 C++中的抽象类及动态类型转换_第4张图片

 

1可将派生类对象截断,只使用继承来的信息(意思是派生对象可以赋值给基类对象,截断自己将继承来的部分赋值给基类)

2但不能将基类对象加长,无中生有变出派生类对象(二基类对象不能赋值给派生类对象,因为radius无从赋值)

那么,下面四个语句的正确与否很显而易见了:

①S = C;          (√)

②C = S;        (×)

③Shape &rS = C;(√)

④Circle &rC = S;     (×)

 

 

 

 

 

不恰当的记录下:(保护属性的数据或函数可被派生类成员访问)

你可能感兴趣的:(C++)