C++编程实践: 抽象基类

本实例来自《C++ Primer Plus》(第六版) 第十三章

题目要求:

假设你正在开发一个图形程序,该程序会显示圆和椭圆等,需要考虑:

  • 椭圆要包含椭圆中心坐标,半长轴,半短轴以及方向角的数据。圆要实现圆心坐标,半径等数据。
  • 椭圆要包含移动,旋转一定角度,计算面积和缩放等方法,但是圆不需要旋转。

设计思路:

  • 虽然圆也是一种椭圆的特殊形势,但是设计成由圆类继承椭圆类显然是十分笨拙的。比较好的办法是涉及一个基类BaseEllipse,圆和椭圆都继承此基类。这样便可以使用指针数组同时管理Circle对象和Ellipse对象、

知识点:

  1. C++通过纯虚函数提供基类未实现的方法,纯虚函数的声明为在函数声明的结尾处添加“=0”,例如基类中的Area方法:

    1. virtual double Area() const = 0;//a pure virtual function
  2. 当类声明中包含纯虚函数的时候,则不能创建该类的对象,包含纯虚函数的类只能作为基类,设计时更多作为接口来使用。
  3. 派生类必须为基类实现纯虚函数的复写(Override),否则不能通过编译。
  4. 要注意当使用基类的指针数组创建管理派生类对象的时候,指针只能指向基类声明过的权限为public的函数,不能使用派生类中的新的成员函数。
  5. 复习一下类产生对象的两种方法

    1. Circle *c = new Circle(1, 0, 1);
    2. Circle d(1, 1, 0);

总结与疑问:

  • 抽象基类一般被用作接口来使用,抽象基类不能实例化对象,包含至少一个纯虚函数的类叫做抽象基类。
  • 如果使用抽象基类的指针数组来管理派生类,那么该数组中的指针不能使用派生类中的新方法(即没有在基类中被以任何形式声明过的方法),如果派生类的所有方法都在抽象基类中声明,又会有些类不会用到接口的全部方法。带来设计上的冗余。

代码实现:

BaseEllipse.h(由于问题比较简单,所有函数均使用内联函数,只为了说明设计的思路)

  1. #pragma once
  2. //基类指针指向派生类的时候,不能使用派生类新定义的函数的问题。
  3. class BaseEllipse {
  4. private:
  5. double x;
  6. double y;
  7. public:
  8. BaseEllipse(double x0 = 0,double y0 = 0):x(x0),y(y0){}
  9. virtual ~BaseEllipse(){}
  10. void Move(int nx, int ny) { x = nx; y = ny; }
  11. virtual double Area() const = 0;//a pure virtual function
  12. virtual void Scale(double sa, double sb){};
  13. virtual void Scale(double sr){}
  14. virtual void Rotate(double nang){}
  15. };
  16. class Ellipse :public BaseEllipse {
  17. private:
  18. double a;
  19. double b;
  20. double angle;
  21. public:
  22. Ellipse(double x0 = 0, double y0 = 0, double a0 = 0, double b0 = 0, double angle0 = 0) :BaseEllipse(x0, y0) { a = a0; b = b0; angle = angle0; }
  23. virtual double Area() const { return 3.14*a*b; }
  24. virtual void Scale(double sa, double sb) { a *= sa; b *= sb; }
  25. virtual void Rotate(double nang) { angle += nang; }
  26. };
  27. class Circle :public BaseEllipse {
  28. private:
  29. double r;
  30. public:
  31. Circle(double x0=0, double y0=0, double r0=0) :BaseEllipse(x0, y0) { r = r0; }
  32. virtual double Area() const { return 3.14*r*r; }
  33. virtual void Scale(double sr) { r *= sr; }
  34. };

来自为知笔记(Wiz)

时间: 2024-12-24 23:26:30

C++编程实践: 抽象基类的相关文章

C++ 纯虚函数与抽象基类

在C++ 中,虚函数可以很好的实现多态,然而也有一定的局限,这个局限在于,虚函数必须在基类中定义,哪怕是空的实现. 例如下面这段代码编译时就会出错: class Base { virtual void print(); }; class Derived:Base { void print() { cout << "Derived" <<endl; } }; 因为Base类中的虚函数print()没有定义. 而在实际编程时我们往往会遇到无法给基类的函数定义的情况,

OOP2(虚函数/抽象基类/访问控制与继承)

通常情况下,如果我们不适用某个函数,则无需为该函数提供定义.但我们必须为每个虚函数都提供定义而不管它是否被用到了,这因为连编译器也无法确定到底会适用哪个虚函数 对虚函数的调用可能在运行时才被解析: 当某个虚函数通过指针或引用调用时,编译器产生的代码直到运行时才能确定应该调用哪个版本的函数.被调用的函数是与之绑定到指针或引用上的对象的动态类型相匹配的那一个 注意:动态绑定只有当我们通过指针或引用调用虚函数时才会发生.当我们通过一个具有普通类型(非引用非指针)的表达式调用虚函数时,在编译时就会将调用

Java类加载器( CLassLoader ) 死磕 3: 揭秘 ClassLoader抽象基类

[正文]Java类加载器(  CLassLoader ) 死磕3:  揭秘 ClassLoader抽象基类 3.1. 揭秘ClassLoader抽象基类 3.1.1. 类的加载分类:隐式加载和显示加载 java中类是动态加载的,jvm启动的时候,并不会一次性加载所有的class文件,而是根据需要去动态加载.一是加快启动的速度,二是节约内存.如果一次性加载全部jar包的所有class,速度会很慢. 动态载入一个class类,有两种方式: (1) implicit隐式加载 即通过实例化才载入的特性来

C# 面向对象 , 抽象基类

抽象基类 关键字,  abstract abstract class SSS { public void aaa() { } } 作为抽象基类, 只能在 继承关系 中 担任父类的角色,不能出现在其他地方. 不能建对象. 抽象类里面的 方法(函数)不能直接实现, 必须在子类实现. 关键字  override ---------只对属性有用(带大括号的) class override EEE : SSS { public void aaa() { } } 抽象新建 SSS p = new EEE()

6、面向对象以及winform的简单运用(抽象基类与接口)

抽象类与抽象方法 1.书写规范: 在类前面加上abstract关键字,就成为了抽象类:在一个方法前面加上abstract关键字,就成为了抽象方法(抽象方法不能有实现方法,直接在后面加分号) 例: abstract class Chouxiang //抽象类 { public abstract void fangfa(); //抽象方法 } 2.抽象类的注意事项: 1)当一个类变为抽象类之后就不能作为对象来使用了,无法new出来 2)抽象方法必须放在抽象类里面(但抽象类中不一定有抽象方法) 3)没

C++抽象基类

抽象类定义: 成员函数至少有一个为纯虚函数(函数声明后面加=0,但是不定义)的类为抽象基类,这个基类不能被显示创建其对象.但是这个基类的其他函数都可以正常定义,一般析构函数为虚函数用来被其他类继承. 例如: 头文件: #ifndef COMMUNICATER_H #define COMMUNICATER_H class Communicater { public: Communicater(void); virtual void run_collect() = 0; virtual ~Commu

Python 接口:从协议到抽象基类

抽象基类的常见用途:实现接口时作为超类使用.然后,说明抽象基类如何检查具体子类是否符合接口定义,以及如何使用注册机制声明一个类实现了某个接口,而不进行子类化操作.最后,说明如何让抽象基类自动“识别”任何符合接口的类——不进行子类化或注册. Python文化中的接口和协议 接口在动态类型语言中是怎么运作的呢?首先,基本的事实是,Python语言没有 interface 关键字,而且除了抽象基类,每个类都有接口:类实现或继承的公开属性(方法或数据属性),包括特殊方法,如__getitem__ 或 _

6.1 numbers--数值抽象基类

6. 数值和数学库 本库主要提供了数值和数学相关的函数处理以及数据类型.numbers模块定义了抽象的数值类型,math和cmath模块主要包括不同的数学函数,比如用来计算浮点数和复数.decimal模块支持十进制数值表示,可以用任何精度进行运算. 6.1 numbers--数值抽象基类 本模块主要按文档(PEP 3141)定义了数值抽象基类. class numbers.Number 数值类的基类,如果你只是想检查一个参数x是否是Number类型,可以使用函数isinstance(x, Num

五、抽象基类与接口

5.1 抽象类与抽象方法 在一个类前面加上“abstract”关键字,此类就成为了抽象类. 对应的,一个方法类前面加上“abstract”关键字,此方法就成为了抽象方法. abstract class Fruit   //抽象类 { public abstract void GrowInArea();  //抽象方法 } 注意抽象方法不能有实现代码,在函数名后直接跟一个分号. 抽象类专用于派生出子类,子类必须实现抽象类所声明的抽象方法,否则,子类仍是抽象类. 抽象类一般用于表达一种比较抽象的事物