2009-04-17 59 views
148

东西,我发现自己经常做的最近被宣布类型定义相关的是类中的某一类,即C++中的内部typedefs - 风格好还是风格不好?

class Lorem 
{ 
    typedef boost::shared_ptr<Lorem> ptr; 
    typedef std::vector<Lorem::ptr> vector; 

// 
// ... 
// 
}; 

这些类型然后在代码的其他地方使用:

Lorem::vector lorems; 
Lorem::ptr lorem(new Lorem()); 

lorems.push_back(lorem); 

的原因,我喜欢它:

  • 它减少了由类模板引入的噪音,std::vector<Lorem>变成Lorem::vector
  • 它用作意图声明 - 在上面的示例中,Lorem类旨在通过boost::shared_ptr进行引用计数并存储在向量中。
  • 它允许实现更改 - 即,如果需要更改Lorem以在后续阶段侵入引用计数(通过boost::intrusive_ptr),那么这会对代码产生最小的影响。
  • 我认为它看起来'漂亮',可以说更容易阅读。

的原因,我不喜欢它:

  • 有时对于依赖关系问题 - 如果你要嵌入,比方说,另一个类而只需要内Lorem::vector(或希望)转发声明Lorem(而不是引入对它的头文件的依赖),那么你最终不得不使用显式类型(例如boost::shared_ptr<Lorem>而不是Lorem::ptr),这有点不一致。
  • 它可能不是很常见,因此难以理解?

我试着用我的编码风格来客观,所以最好能对它有一些其他的看法,这样我就可以剖析我的想法了。

回答

131

我认为这是优秀的风格,我自己使用它。尽可能限制名称范围总是最好的,并且类的使用是在C++中执行此操作的最佳方式。例如,C++标准库大量使用类中的typedef。

+0

这是一个很好的观点,我不知道它看起来'漂亮'是我的潜意识细微地指出范围有限是一件好事。不过,我想知道STL在课堂模板中主要使用它的事实是否会使其具有细微差别?在“具体”课堂中辩解更难吗? – 2009-04-17 08:55:11

+1

那么标准库是由模板而不是类组成的,但我认为两者的理由是相同的。 – 2009-04-17 09:38:03

2

我建议将这些类型定义移到类之外。这样,您可以删除对共享指针和向量类的直接依赖关系,只有在需要时才可以包含它们。除非您在类实现中使用这些类型,否则我认为它们不应该是内部类型定义。

您喜欢它的原因仍然匹配,因为它们是通过typedef类型别名解决的,而不是通过在类中声明它们。

+0

这会使用typedefs监听匿名命名空间吗?! typedef的问题是它隐藏了实际的类型,当被包含在多个模块中时,会导致冲突,而这些模块很难找到/修复。将这些包含在名称空间或类内部是一种很好的做法。 – Indy9000 2009-04-17 08:38:24

+3

名称冲突和匿名命名空间污染与在类内部或外部保留类型名称无关。你可以与你的类名称冲突,而不是你的类型定义。所以为了避免名称污染,请使用名称空间。在名称空间中声明您的类和相关的typedef。 – 2009-04-17 08:53:14

+0

在类中放入typedef的另一个参数是使用模板化函数。例如,当一个函数收到一个包含未知字符串类型(字符串或您自己的字符串一致变体)的未知容器类型(向量或列表)时。找出容器有效载荷类型的唯一方法是使用typedef'value_type',它是容器类定义的一部分。 – Marius 2009-12-23 19:15:24

0

当typedef仅用于类本身(即声明为private)时,我认为它是一个好主意。但是,正是由于你给出的原因,如果typedef需要在课堂外知道,我不会使用它。在这种情况下,我建议将它们移出课堂。

7

Typdefs绝对是很好的风格。而你所有的“我喜欢的理由”都是好的和正确的。

关于您遇到的问题。那么,前向宣言不是一个圣杯。您可以简单地设计代码以避免多级别依赖性。

你可以在类之外移动typedef,但Class :: ptr比ClassPtr漂亮得多,所以我不这样做。就像我的命名空间一样 - 事物在范围内保持连接。

有时候我做

Trait<Loren>::ptr 
Trait<Loren>::collection 
Trait<Loren>::map 

,它可以默认为所有域类和一些专门为特定的人。

3

STL始终执行此类操作 - typedef是STL中许多类的接口的一部分。

reference 
iterator 
size_type 
value_type 
etc... 

都是类型定义,它们是各种STL模板类的接口的一部分。

3

对此的另一投票是一个好主意。在编写一个在时间和空间上都必须高效的仿真时,我开始这样做。所有的值类型都有一个Ptr typedef,它起始于一个boost共享指针。然后,我做了一些分析,并将其中的一些更改为boost侵入指针,而无需更改使用这些对象的任何代码。

请注意,这仅适用于您知道将在哪些类中使用,并且所有用途具有相同要求的情况。例如,我不会在库代码中使用它,因为您无法知道何时将该库用于将要使用的上下文。

9

它作为意图的声明 - 在上面的例子中,类的Lorem 旨在是参考经由升压:: shared_ptr的计数 并存储在 矢量。

这正是它所做的不是做的。

如果我在代码中看到'Foo :: Ptr',我完全不知道它是shared_ptr还是Foo *(STL has :: pointer typedefs是T *,请记住)或其他。 特别如果它是一个共享指针,我根本不提供typedef,但明确地在代码中使用shared_ptr。

其实,我很少使用Template Metaprogramming之外的typedefs。

的STL做这种类型的东西都

STL的设计,在成员函数和嵌套类型定义来定义的概念,是一个历史的死路,现代模板库使用免费时间函数和traits类(参考Boost.Graph),因为它们不排除内置类型对概念建模的影响,并且因为它使得在设计时不考虑给定模板库的概念的类型变得更容易。

不要使用STL作为犯同样错误的理由。

1

目前我正在研究的代码,密集使用这些类型的定义。到目前为止,这很好。

但我注意到,经常有迭代类型定义,这些定义被分成几个类,并且你永远不知道你在处理什么类型。我的任务是总结隐藏在这些typedef背后的一些复杂数据结构的大小 - 所以我不能依赖现有的接口。结合三到六层的嵌套命名空间,然后变得混乱。

所以在使用前,有几点需要考虑

  • 没有任何人需要这些类型定义?这个类是否被其他类使用了很多?
  • 我是否缩短使用量或隐藏课程? (在隐藏的情况下你也可以想到接口。)
  • 其他人使用的代码?他们是如何做到的呢?他们会认为它更容易还是会变得困惑?