Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用预处理器声明多个类似的类是一种良好的做法吗?_C++_C Preprocessor - Fatal编程技术网

C++ 使用预处理器声明多个类似的类是一种良好的做法吗?

C++ 使用预处理器声明多个类似的类是一种良好的做法吗?,c++,c-preprocessor,C++,C Preprocessor,假设我想创建一个数学库。我需要在不同维度中操作向量,因此我希望每个维度有一个类(也称为Vector2,Vector3,Vector4) 到目前为止还不错。但这将导致严重的代码重复,因为Vector3主要是一个Vector2,在某些函数中使用了z属性 所以我有个主意。代码复制是机器的任务,而不是人类的任务,因此我可以写以下内容: 在Vector.hpp中: #ifndef VECTOR_HPP #define VECTOR_HPP #define VECTOR_DIM 2 #include "_

假设我想创建一个数学库。我需要在不同维度中操作向量,因此我希望每个维度有一个类(也称为
Vector2
Vector3
Vector4

到目前为止还不错。但这将导致严重的代码重复,因为
Vector3
主要是一个
Vector2
,在某些函数中使用了
z
属性

所以我有个主意。代码复制是机器的任务,而不是人类的任务,因此我可以写以下内容:

在Vector.hpp中:

#ifndef VECTOR_HPP
#define VECTOR_HPP

#define VECTOR_DIM 2
#include "_Vector.hpp"
#define VECTOR_DIM 3
#include "_Vector.hpp"
#define VECTOR_DIM 4
#include "_Vector.hpp"
#undef VECTOR_DIM

#endif
// This header was not protected from multiple inclusions on purpose

#define VECTOR_NAME Vector ## VECTOR_DIM

class VECTOR_NAME
{
public:
    // Some methods here ...

    float x;
    float y;
#if VECTOR_DIM >= 3
    float z;
#endif
#if VECTOR_DIM >= 4
    float w;
#endif
};

#undef VECTOR_NAME
在_Vector.hpp中:

#ifndef VECTOR_HPP
#define VECTOR_HPP

#define VECTOR_DIM 2
#include "_Vector.hpp"
#define VECTOR_DIM 3
#include "_Vector.hpp"
#define VECTOR_DIM 4
#include "_Vector.hpp"
#undef VECTOR_DIM

#endif
// This header was not protected from multiple inclusions on purpose

#define VECTOR_NAME Vector ## VECTOR_DIM

class VECTOR_NAME
{
public:
    // Some methods here ...

    float x;
    float y;
#if VECTOR_DIM >= 3
    float z;
#endif
#if VECTOR_DIM >= 4
    float w;
#endif
};

#undef VECTOR_NAME

这将大大简化任务,但这是一种好的做法吗?

鉴于您发布的代码,您可以轻松地用以下代码替换它,而不必使用预处理器技巧

template <int dim> struct Data;

template <> struct Data<2>
{
   float x;
   float y;
};

template <> struct Data<3> : Data<2>
{
   float z;
};

template <> struct Data<4> : Data<3>
{
   float w;
};

template <int dim> class Vector
{
   public:
      // Some methods here ...
      Data<dim> data;
};
模板结构数据;
模板结构数据
{
浮动x;
浮动y;
};
模板结构数据:数据
{
浮动z;
};
模板结构数据:数据
{
浮动w;
};
模板类向量
{
公众:
//这里有一些方法。。。
数据;
};
您可以轻松扩展
向量
数据
,以支持更多功能

不仅如此,您还可以在实例化
Vector
时防止
dim
的无效值,方法是确保
Data
仅为
dim
的预设有效值集定义
dim

功能上的相似性会导致代码中的重复? 考虑到帖子标题中的问题,“使用预处理器良好实践声明多个类似类吗?”首先,让我们看看是否应该消除重复。是的,您读对了-,这取决于副本的上下文

作为经验法则

  • 巧合的复制应保留
  • 应排除系统性的重复
请注意,“巧合”并不意味着“意外”。相反,偶然重复的代码通常会有意识地编写。关键的一点是,类似的功能没有一个基本的共同原则。因此,即使它们今天碰巧是相似的,它们能够独立进化也是很重要的

还要注意,“系统化”并不一定意味着你已经计划好了。这与“系统错误”中的“系统性”相同,即重复是由于潜在的共同原则造成的,无论是否有意识

载体 应用于你在问题描述中给出的例子,数学库中不同维度的向量类型,可以说很多重复都是系统类型的,应该消除。但在其他情况下,它可能不会如此清晰

如何消除不必要的重复? 我们可以使用的工具 如果它发生在编译时,您在C中的选项将受到限制。但是,你把这个问题标记为<强> C++ >强>一个,即使C和C++共享他们的预编译器,C++也有更多的功能:内联函数、实用型和最后但不是最少的模板类和模板函数。 已经很好地展示了如何将模板应用到您的案例中。更多的是可能的模板:在C++中,有一个完整的开发学科,叫做“模板元编程”。 与快速使用预处理器相比,使用模板解决方案要困难一些。那么,为什么要选择模板而不是预处理器宏和包含

想想你的(图书馆)用户 对于只供自己使用且不需要大量维护的代码来说,获得“有效”的东西可能就足够了。但是如果您正在编写一个库,那么当用户在使用该库时出现可检测到的错误时,他们会希望得到编译器的通知。作为推论,您需要知道,当以无错误编译的方式调用库时,它会执行一些有意义的操作。对于非平凡逻辑,要正确使用宏是非常困难的,因为您必须考虑以下几个问题:

  • 保证类型安全
  • 如果宏带有参数,那么这些参数还会是宏吗
  • 如果宏采用参数,那么这些参数可以是函数调用还是方法调用?
    • 如果这些功能有副作用呢?(您必须小心,即使宏可能多次使用函数的返回值,也不会多次调用函数。)
  • 宏没有名称空间,因此必须通过名称前缀约定来避免冲突

虽然使用模板一开始可能很难获得有效的东西,但使用makros获得正确有效的东西要比使用makros容易得多。出于其他答案中提到的原因,我建议不要这样做(使用模板可能是更好的选择)。也就是说,在某些情况下,预处理器和宏可能会派上用场。我已经成功地使用了宏,在这种情况下,我知道类似于代码的类很小,不太可能更改(声明和实现)或被继承,并且使用模板实现会很难编写/理解,因此更容易出现错误。事实上,这段代码还没有被再次触动,工作顺利,我仍然认为宏是最好的选择


不过,根据问题中提供的信息,我觉得你没有这种情况。但是,使用任何对你有用的东西,特别是当它是一个个人项目时:如果它在将来咬到你,你就会学到一些东西