封装与结构 - 这被认为是不好的风格?

时间:2012-01-27 20:40:20

标签: c++ cuda

我在CUDA项目中有很多课程,这些课程主要是美化struct并且通过作文相互依赖:

class A {
    public:
        typedef boost::shared_ptr<A> Ptr;
        A(uint n_elements) { ... // allocate element_indices };
        DeviceVector<int>::iterator get_element_indices();
    private:
        DeviceVector<int> element_indices;
}

class B {
    public:
        B(uint n_elements) { 
            ... // initialize members
        };
        A::Ptr get_a();
        DevicePointer<int>::iterator get_other_stuff();
    private:
        A::Ptr a;
        DeviceVector<int> other_stuff;
}

DeviceVector只是thrust::device_vector的包装器,::iterator可以转换为原始设备指针。这是必需的,因为调用了定制内核并需要处理设备内存。

现在,我确实关心封装,但是

  • 必须公开指向数据的原始指针,因此使用AB的类可以在GPU上运行自定义内核
  • 不需要默认构造函数,应自动分配设备内存 - &gt; shared_ptr<T>
  • 只需要AB上的极少数方法

因此,只需使用结构

就可以简化生活
struct A {
    void initialize(uint n_elements);
    DeviceVector<int> element_indices;
}

struct B {
    void initialize(uint n_elements);
    A a;
    DeviceVector<int> other_stuff;
}

我想知道我是否正确,在封装意义上,这实际上是等同的。如果是这样,那么整个概念是否存在任何问题,并且可能会在某些时候出现问题?

3 个答案:

答案 0 :(得分:2)

简单。在您需要之前不要引入抽象和封装。

答案 1 :(得分:2)

始终将您的数据成员设为私有是一个好习惯。最初看起来你的结构很小,没有或有几个成员函数,并且需要公开数据成员。然而,随着你的程序的发展,这些“结构”往往会增长和扩散。在您知道它之前,您的所有代码都依赖于其中一个结构的内部结构,并且稍微更改它将在整个代码库中产生反响。

即使您需要公开指向数据的原始指针,通过getter实现这一点仍然是个好主意。您可能想要更改内部处理数据的方式,例如: G。用std :: vector替换原始数组。如果您的数据成员是私有的并且您正在使用getter,则可以在不影响使用您的类的任何代码的情况下执行此操作。此外,getters允许您强制执行constine,并通过返回const指针使特定的数据片段成为只读。

预计会有更多的工作,但从长远来看大部分时间都会得到回报。

答案 2 :(得分:1)

这是一种权衡。

使用值结构可以是将大量数据组合在一起的一种非常简单的方法。如果你开始研究许多辅助程序并依赖它们超出预期用途,它们就会非常糟糕。对于何时以及如何使用它们要严格要求,并且它们很好。对这些对象采用零方法是一种让自己明白的好方法。

您可能有一些用于解决问题的类,我将其称为模块。在模块中具有价值结构很容易推理。在模块之外,你必须希望有良好的行为。你没有严格的接口,所以你不得不希望编译器会警告你滥用。

鉴于该声明,我认为它们更适合匿名或详细的命名空间。如果他们最终进入公共界面,人们往往会向他们添加糖。删除糖或将其重构为带接口的第一类对象。

我认为它们更适合作为const对象。你遇到的问题是你(试图)保持这个“对象”的不变性,无论它在整个生命周期中使用到哪里。如果不同的抽象级别希望它们具有轻微的突变,请复制。命名参数成语对此有利。

Domain Driven Design对这个问题进行深思熟虑的彻底处理。它的特点是如何理解和促进设计更实际的意义。

Clean Code也从不同的角度讨论了这个主题。它更像是一本morality书。

两者都是很棒的书籍,并且通常会在本主题之外推荐。