C/C++细节问题(bug调试)以动态绑定代码来示例

简介:

在程序界,有句话是,程序好些,bug难调。

很多bug并不一点是逻辑错误,而是一些细节问题。

我们分析下三个细节错误引起的无法运行问题:

1
//#define M_PI 3. 14159265358979323846      3.14中间有个空格

1
\t        写成了\ t       有个空格

首先,创建了一个新类型CFigure。我们想创建一些具体的图形(如,三角形、正方形或者圆),以及计算这些图形周长和面积的方法。但是,我们并不知道具体的图形是什么类型,所以无法用方法直接计算图形的这些特性。这就是要把CFigure类创建为抽象类的原因。抽象类是至少声明了一个虚方法的类,该虚方法没有实现,且其原型后面有=0。以这种方式声明的函数叫做纯虚函数。抽象类不能有对象,但是可以有继承类。因此可以实例化抽象类的指针和引用,然后从CFigure类派生出CTriangle、CSquare和CCircle类,分别表示三角形、正方形和圆形。

我们要实例化这些对象的类型,所以在这些派生类中,实现了FigureType方法、Circumference方法和Area方法。虽然这3个类中的方法名都相同,但是它们的实现不同,这与覆盖类似但含义不同。

如何理解?在本例的main函数中,声明了一个数组,内含3个CFigure类型的指针。作为指向基类的指针或引用,它们一定可以指向该基类的任何派生类。因此,可以创建一个CTriangle类型的对象,并设置CFigure类型的指针指向它,

1
CFigure* figures[3];

同理,用下面的代码可以设置其他图形:

1
2
3
figures[0] =  new  CTriangle(2.1,3.2,4.3);
figures[1] =  new  CSquare(5.4,6.6);
figures[2] =  new  CCircle(8.9);

现在,考虑下面的代码:

1
2
3
4
5
6
7
for  ( int  i = 0; i < 3; i++)
     {
         cout <<  "Figure type:\t"  << figures[i]->FigureType();
         cout<<  "\nCircumference:\t"  << figures[i]->Circumference();
         cout<<  "\nArea:\t\t"  << figures[i]->Area();
         cout<< endl << endl;
     }

编译器将使用C++的动态绑定(dynamicbinding)特性,确定图形指针具体指向哪个类型的对象,调用合适的虚方法。只有把方法声明为虚方法,且通过指针或引用访问才能使用动态绑定。


全部代码如下,直接可以编译运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "stdafx.h"
#include < iostream>
#include <tchar.h> 
#define M_PI 3.14159265358979323846
using  namespace  std;
//#define M_PI 3. 14159265358979323846      3.14中间有个空格
 
class  CFigure   //base class
{
public :
     virtual  char * FigureType() = 0;
     virtual  double  Circumference() = 0;
     virtual  double  Area() = 0;
     virtual  ~CFigure()
    
     
     }
};
 
class  CTriangle :  public  CFigure  //Derived Class
{
public :
     CTriangle()
     {
         a = b = c = 0;
     }
     CTriangle( double  a,  double  b,  double  c) : a(a), b(b), c(c) { }
 
     virtual  char * FigureType()
     {
         return  "Triangle" ;
     }
     virtual  double  Circumference()
     {
         return  a + b + c;
     }
     virtual  double  Area()
     {
         double  S = Circumference() / 2;
         return  sqrt (S * (S - a) * (S - b) * (S - c));
     }
private :
     double  a, b, c;
};
class  CSquare :  public  CFigure   //Derived Class
{
public :
     CSquare()
     {
         a = 0.0;
         b = 0.0;
     }
     CSquare( double  a,  double  b) : a(a), b(b)
     {
 
     }
     virtual  char * FigureType()
     {
         return  "Square" ;
     }
     virtual  double  Circumference()
     {
         return  2 * a + 2 * b;
     }
     virtual  double  Area()
     {
         return  a * b;
     }
private :
     double  a, b;
};
class  CCircle :  public  CFigure  //Derived Class
{
private :
     double  r;
 
public :
     CCircle()
     {
         r = 0;
     }
     CCircle( double  r) : r(r)
     {
 
     }
     virtual  char * FigureType()
     {
         return  "Circle" ;
     }
     virtual  double  Circumference()
     {
         //return 2 * r * M_PI;
         double  res = 0.00000000000000000000000;
         res = 2 * r * M_PI;
         //res = 2 * r *  3. 141592;
         return  res;
 
     }
     virtual  double  Area()
     {
         double  res = 0.000000000000000000000;
         res = 2 * r * M_PI;
         //res = 2 * r *  3. 14159265358979323846;
         return  res;
 
     }
 
};
int  _tmain( int  argc, _TCHAR* argv[]) 
{
     CFigure* figures[3];
     figures[0] =  new  CTriangle(2.1,3.2,4.3);
     figures[1] =  new  CSquare(5.4,6.6);
     figures[2] =  new  CCircle(8.9);
 
     for  ( int  i = 0; i < 3; i++)
     {
         cout <<  "Figure type:\t"  << figures[i]->FigureType();
         cout<<  "\nCircumference:\t"  << figures[i]->Circumference();
         cout<<  "\nArea:\t\t"  << figures[i]->Area();
         cout<< endl << endl;
     }
 
     getchar ();
     return  0;
}

运行结果:

wKioL1mw88jhKufqAADRNwBXBuc826.jpg-wh_50


本文转自 liam2199 博客,原文链接:  http://blog.51cto.com/liam2199/1963425         如需转载请自行联系原作者


相关文章
|
5月前
|
C++
C++ 语言异常处理实战:在编程潮流中坚守稳定,开启代码可靠之旅
【8月更文挑战第22天】C++的异常处理机制是确保程序稳定的关键特性。它允许程序在遇到错误时优雅地响应而非直接崩溃。通过`throw`抛出异常,并用`catch`捕获处理,可使程序控制流跳转至错误处理代码。例如,在进行除法运算或文件读取时,若发生除数为零或文件无法打开等错误,则可通过抛出异常并在调用处捕获来妥善处理这些情况。恰当使用异常处理能显著提升程序的健壮性和维护性。
94 2
|
5月前
|
算法框架/工具 C++ Python
根据相机旋转矩阵求解三个轴的旋转角/欧拉角/姿态角 或 旋转矩阵与欧拉角(Euler Angles)之间的相互转换,以及python和C++代码实现
根据相机旋转矩阵求解三个轴的旋转角/欧拉角/姿态角 或 旋转矩阵与欧拉角(Euler Angles)之间的相互转换,以及python和C++代码实现
455 0
|
2月前
|
算法 安全 C++
提高C/C++代码的可读性
提高C/C++代码的可读性
76 4
|
3月前
|
Linux C语言 C++
vsCode远程执行c和c++代码并操控linux服务器完整教程
这篇文章提供了一个完整的教程,介绍如何在Visual Studio Code中配置和使用插件来远程执行C和C++代码,并操控Linux服务器,包括安装VSCode、安装插件、配置插件、配置编译工具、升级glibc和编写代码进行调试的步骤。
550 0
vsCode远程执行c和c++代码并操控linux服务器完整教程
|
4月前
|
C++
2合1,整合C++类(Class)代码转换为MASM32代码的平台
2合1,整合C++类(Class)代码转换为MASM32代码的平台
|
4月前
|
C++
继续更新完善:C++ 结构体代码转MASM32代码
继续更新完善:C++ 结构体代码转MASM32代码
|
4月前
|
C++ Windows
HTML+JavaScript构建C++类代码一键转换MASM32代码平台
HTML+JavaScript构建C++类代码一键转换MASM32代码平台
|
4月前
|
前端开发 C++ Windows
C++生成QML代码与QML里面集成QWidget
这篇文章介绍了如何在C++中生成QML代码,以及如何在QML中集成QWidget,包括使用Qt Widgets嵌入到QML界面中的技术示例。
|
5月前
|
程序员 C++ 开发者
C++命名空间揭秘:一招解决全局冲突,让你的代码模块化战斗值飙升!
【8月更文挑战第22天】在C++中,命名空间是解决命名冲突的关键机制,它帮助开发者组织代码并提升可维护性。本文通过一个图形库开发案例,展示了如何利用命名空间避免圆形和矩形类间的命名冲突。通过定义和实现这些类,并在主函数中使用命名空间创建对象及调用方法,我们不仅解决了冲突问题,还提高了代码的模块化程度和组织结构。这为实际项目开发提供了宝贵的参考经验。
83 2
|
5月前
|
C++
拥抱C++面向对象编程,解锁软件开发新境界!从混乱到有序,你的代码也能成为高效能战士!
【8月更文挑战第22天】C++凭借其强大的面向对象编程(OOP)能力,在构建复杂软件系统时不可或缺。OOP通过封装数据和操作这些数据的方法于对象中,提升了代码的模块化、重用性和可扩展性。非OOP方式(过程化编程)下,数据与处理逻辑分离,导致维护困难。而OOP将学生信息及其操作整合到`Student`类中,增强代码的可读性和可维护性。通过示例对比,可以看出OOP使C++代码结构更清晰,特别是在大型项目中,能有效提高开发效率和软件质量。
43 1