在C ++中为所有对象使用对象(而不是原始类型)是否有意义?


17

在我最近从事的项目中,我不得不使用很多看起来像这样的函数:

static bool getGPS(double plane_latitude, double plane_longitude, double plane_altitude,
                       double plane_roll, double plane_pitch, double plane_heading,
                       double gimbal_roll, double gimbal_pitch, double gimbal_yaw, 
                       int target_x, int target_y, double zoom,
                       int image_width_pixels, int image_height_pixels,
                       double & Target_Latitude, double & Target_Longitude, double & Target_Height);

所以我想重构它看起来像这样:

static GPSCoordinate getGPS(GPSCoordinate plane, Angle3D planeAngle, Angle3D gimbalAngle,
                            PixelCoordinate target, ZoomLevel zoom, PixelSize imageSize)

在我看来,这比第一种方法更具可读性和安全性。但是创建PixelCoordinatePixelSize分类有意义吗?还是我最好只使用std::pair<int,int>每个。上一ZoomLevel堂课有意义double吗,还是我应该只使用一个?

我对所有内容都使用类的背后的直觉是基于以下假设:

  1. 如果所有内容都有类,则不可能ZoomLevelWeight期望对象的地方传递,因此为函数提供错误的参数会更加困难
  2. 同样,某些非法操作也会导致编译错误,例如将a添加GPSCoordinate到a ZoomLevel或另一个GPSCoordinate
  3. 合法操作将易于表示且类型安全。即减去两个GPSCoordinates将产生一个GPSDisplacement

但是,我见过的大多数C ++代码都使用很多原始类型,我想一定有充分的理由。将对象用于任何事物是个好主意,还是有我不知道的缺点?


8
“我见过的大多数C ++代码都使用了很多原始类型” –我想到了两个想法:很多C ++代码是由熟悉C且抽象性较弱的程序员编写的;也是
St

3
我认为这是因为原始类型简单,直接,快速,流畅且高效。现在在OP的示例中,引入一些新类绝对是一个好主意。但是标题问题的答案(在其中说“一切”)是不可接受的!
李斯特先生,2013年

1
@Max typedeffing doubles绝对不能解决OP的问题。
李斯特先生,2013年

1
@CongXu:我的想法几乎相同,但更多的意义是“程序员在构建抽象方面有问题,可能编写了任何语言的大量代码”。
布朗

1
俗话说“如果您有一个带有17个参数的函数,则可能会错过一些”。
Joris Timmermans 2013年

Answers:


24

当然是。带有过多参数的函数/方法是代码嗅觉,它指示以下至少一项:

  1. 函数/方法一次执行太多操作
  2. 函数/方法需要访问很多东西,因为它是在询问,不告诉或违反某些OO设计法则
  3. 这些论点实际上是密切相关的

如果是最后一种情况(您的示例确实表明了这一点),那么是时候做一些花哨的裤子“抽象”了,这是几十年前好孩子在谈论的哦。实际上,我将比您的示例更进一步,并执行以下操作:

static GPSCoordinate getGPS(Plane plane, Angle3D gimbalAngle, GPSView view)

(我对GPS并不熟悉,因此这可能不是正确的抽象;例如,我不知道缩放与所谓的函数有什么关系getGPS。)

请喜欢类,如PixelCoordinate超过std::pair<T, T>,即使两个具有相同的数据。它增加了语义值,外加一些额外的类型安全性(即使两个都是s,编译器也会阻止您将a传递ScreenCoordinate给a 。PixelCoordinatepair


1
更不用说您可以通过较大的结构来参考所有酷孩子尝试做的一点微优化,但实际上不应该
棘轮异常

6

免责声明:我更喜欢C而不是C ++

代替类,我将使用结构。由于结构和类几乎相同(请参见此处获取简单图表或此SO问题),所以这一点充其量是有益的,但是我认为区别是有好处的。

C程序员熟悉结构作为分组的数据块,这些数据在分组时具有更大的含义,而当我看到一个clasas时,我假设存在一些内部状态和操作该状态的方法。GPS坐标没有状态,只有数据。

从您的问题来看,这似乎正是您要寻找的东西,它是一个通用容器,而不是有状态结构。正如其他人所提到的,我不会费心将Zoom放入自己的类中。我个人讨厌构建用于保存数据类型的类(我的教授喜欢创建HeightId类)。

如果所有内容都有类,则不可能在需要Weight对象的地方传递ZoomLevel,因此为函数提供错误的参数会更加困难

我认为这不是问题。如果您通过对已完成的显而易见的事情进行分组来减少参数的数量,则标头应该足以防止出现这些问题。如果您真的很担心,请使用结构将原始函数分开,这样可以为常见错误提供编译错误。彼此相邻地交换两个参数很容易,但是如果它们相距较远,则更难。

同样,某些非法操作也会导致编译错误,例如将GPSCoordinate添加到ZoomLevel或另一个GPSCoordinate

善用运算符重载。

合法操作将易于表示且类型安全。即减去两个GPSCoordinates将产生一个GPSDisplacement

还可以很好地利用运算符重载。

我认为您在正确的轨道上。另一件事要考虑的是它如何适合程序的其余部分。


3

使用专用类型的优点是,很难弄清楚参数的顺序。例如,示例函数的第一个版本以9个double的链开始。当有人使用此功能时,很容易搞乱命令并通过万向架角度来代替GPS坐标,反之亦然。这可能会导致非常奇怪且难以跟踪的错误。当仅传递三个具有不同类型的参数时,编译器可能会捕获此错误。

实际上,我会考虑更进一步,介绍技术上相同但语义不同的类型。例如,通过一个类PlaneAngle3d和一个单独的类GimbalAngle3d,即使它们都是三个双精度值的集合。除非是有意的,否则这将使得无法将另一个用作另一个。

我建议使用typedef,它只是原始类型(typedef double ZoomLevel)的别名,不仅出于这个原因,而且还有另一个原因:它可以轻松地让您以后更改类型。有一天,当您想到使用float可能效果一样好,double但在内存和CPU效率上可能更高时,您只需要在一个地方更改它,而不用成批更改。


+1为typedef建议。让您两全其美:原始类型和对象。
Karl Bielefeldt

改变类成员的类型并不比typedef难。还是与原始语言相比?
MaHuJa 2013年

2

这里已经有了很好的答案,但是我想补充一件事:

使用PixelCoordinatePixelSize类使事情变得非常具体。一般CoordinatePoint2D课程可能更适合您的需求。A Point2D应该是实现最常见的点/矢量运算的类。您甚至可以通用地实现这样的类(Point2D<T>其中T可以是intdouble或其他东西)。

2D点/矢量操作在许多2D几何编程任务中非常普遍,以我的经验,这样的决定将大大增加重用现有2D操作的机会。你会避免重新实现它们每个的需求PixelCoordinateGPSCoordinate“Whatsover” -协调类连连。


1
struct PixelCoordinate:Point2D<int>如果您想要适当的类型安全性,也可以这样做
棘轮怪胎

0

所以我想重构它看起来像这样:

static GPSCoordinate getGPS(GPSCoordinate plane, Angle3D planeAngle, Angle3D gimbalAngle,
                        PixelCoordinate target, ZoomLevel zoom, PixelSize imageSize)

在我看来,这比第一种方法更具可读性和安全性。

它[更易读]。这也是一个好主意。

但是创建PixelCoordinate和PixelSize类有意义吗?

如果它们代表不同的概念,那么这是有道理的(即“是”)。

或者我最好对每个都使用std :: pair。

您可以从开始做起typedef std::pair<int,int> PixelCoordinate, PixelSize;。这样,您就可以涵盖语义(您正在使用像素坐标和像素大小,而不是在客户端代码中使用std :: pairs进行操作),并且如果需要扩展,只需将typedef替换为一个类,并且客户端代码应需要最少的更改。

拥有ZoomLevel类是否有意义,还是我应该只使用double类?

您也可以对其进行typedef定义,但是double在需要与double关联的功能之前,我将使用- ,例如,具有一个ZoomLevel::default值将要求您定义一个类,但是直到您拥有类似的东西保持两倍)。

我对所有内容都使用类的背后的直觉是基于这些假设[为简洁起见,省略了这些内容]

它们是有力的论据(您应该始终努力使您的界面易于正确使用和难以错误使用)。

但是,我见过的大多数C ++代码都使用很多原始类型,我想一定有充分的理由。

有原因;但是,在很多情况下,这些原因都不是很好。这样做的一个有效原因可能是性能,但这意味着您应该将这种代码视为例外,而不是规则。

将对象用于任何事物是个好主意,还是有我不知道的缺点?

通常最好确保如果您的价值观总是在一起出现(并且毫无区别),则应该将它们组合在一起(出于您在帖子中提到的相同原因)。

也就是说,如果您的坐标始终具有x,y和z,那么拥有一个coordinate类比在任何地方传输三个参数要好得多。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.