【问题标题】:getting around const in an init method在 init 方法中绕过 const
【发布时间】:2011-01-25 11:53:02
【问题描述】:

所以我can't use initializers in my class constructor 因为使用了数组,所以我决定改用init() 方法。现在我有一个不同的问题。我有这样的课:

class EPWM {
private:
   volatile EPWM_REGS* const regs;
public:
   void init(volatile EPWM_REGS* _regs);
};

我需要通过初始化regs = _regs; 来实现init(),但由于const 而我不能。有没有办法在我的 init 方法中强制分配?我想保留 const 关键字,这样我就不会意外地在其他地方重新分配。

编辑: 尽可能多地使用构造函数 + 初始化程序,这将解决这个问题(我的代码曾经这样做),我不能,因为我有另一个类,它有一个数组EPWM 对象,我无法初始化这些对象,因为 C++ 不支持数组成员的初始化程序。 (再次,请参阅the other question I asked a little while ago on this subject.

使用 EPWM 的上下文是这样的:

class PwmGroup {
private:
   EPWM *epwm;

   void init(EPWM *_epwm) { epwm = _epwm; }
};

/* ... */
// main code:

EPWM epwm[3];
PwmGroup pwmGroup;

{
   // EPwm1Regs, EPwm2Regs, EPwm3Regs are structs
   // defined by TI's include files for this processor
   epwm[0].init(&EPwm1Regs);
   epwm[1].init(&EPwm2Regs);
   epwm[2].init(&EPwm3Regs);
   pwmGroup.init(epwm);
}

【问题讨论】:

  • 为什么不在 ctor 中初始化 const regs 成员?它是否依赖于其他数组进行初始化?
  • 我有另一个类,它有一个 EPWM 对象数组,我无法在构造函数中初始化,因为 C++ 不允许这样的事情。
  • 我明白你的问题。演员阵容总是让我对设计三思而后行。
  • 嘿。我现在想了五六次关于这个设计。 :-) 每次我想找到更好的方法时,我总能找到一些回到尝试初始化对象数组的问题。
  • @Jason S:看我的回答。这有帮助吗?

标签: c++ constants


【解决方案1】:

您可以考虑const_cast 和指针,但最好很少使用它非常。比如……

EPWM_REGS** regsPP = const_cast<EPWM_REGS**>(&regs);
*regsPP = _regs;

【讨论】:

  • 这听起来像是其中一种情况。 “*(const_cast(&regs)) = _regs;”怎么样? ?
  • (或 "*(const_cast(&regs)) = _regs;" 在我的情况下,这似乎编译正确。)
  • 这也是不能保证 const_cast 工作的情况之一,因为你要转换的东西实际上是 const (而不是添加 const 例如方法参数) .
【解决方案2】:

使用这样的构造函数:

EPWM::EPWM(volatile EPWM_REGS* _regs)
    : regs(_regs)
{}

然后在 init 中根本没有参数:

void EPWM::init()
{
    // do something with this->regs here...
}

换句话说,您可以在类构造函数中初始化所有内容 - 只是不能初始化成员数组。

【讨论】:

    【解决方案3】:

    下面的呢?

    struct EPWM_array {
      EPWM_array() { /* initialize array */ }
      const EPWM *begin() const;
      const EPWM *end() const;
    
      EPWM array[ 10 ];
    };
    
    struct EPWMWrapper {  
       volatile EPWM_REGS* const regs;
       EPWMWrapper(EPWM_array const& a) : regs(a.begin()) {}
    };
    

    【讨论】:

    • EPWM_array 是应用代码吗?让我们谈谈分区:我想将 EPWM 和 PwmGroup 定义为我可以开始工作并保持不变的库代码。在我的应用程序代码中,我想使用 (EPWM_REGS *) 的特定值配置 PwmGroup / EPWM[3] 的实例,这些值可能会从一个应用程序更改为另一个应用程序,具体取决于我的应用程序如何使用此特定部分的外围设备。如果我理解您的示例,则 EPWM_array() 在其构造函数中处理初始化的细节。不幸的是,按照我想要的方式进行分区,我想我必须使用虚拟子类:-/
    • 嗯....也许不是。有没有办法重写 EPWM_array 所以我不在构造时初始化它的数组成员,而是在稍后的时候?这令人沮丧....
    • @Jason S:当然,为什么不呢?确保在实例化 EPWM_array 之前不实例化 EPWMWrapper。我不确定您是否需要虚拟子类,但可能需要子类化。使用继承有问题吗?在我看来,如果您希望您的用户提供 EPWM_array 实例,那么您的 EPWMWrapper 设计确实应该面向界面。
    • thanks... C++ 接口 + 低端嵌入式处理器不能很好地结合在一起(需要虚拟函数的 vtables,也许这不是一件坏事,但我倾向于远离它们嵌入式世界)。
    • 我知道 VxWorks 上 g++ 的怪癖。归根结底,这取决于您的平台/编译器。但是,我强烈建议您尝试一下,看看是否遇到问题。
    【解决方案4】:

    这样的东西会有帮助吗?您仍然可以故意违反 constness,但它可以防止普通人犯愚蠢的错误(我还没有编译过)。

    class EPWM {
    private:
       volatile EPWM_REGS* regs_for_init_never_use;
       volatile EPWM_REGS* const& regs;
    public:
       EPWM() : regs(regs_for_init_never_use)
       void init(volatile EPWM_REGS* _regs);
    };
    

    【讨论】:

    • 有趣....我不得不查看它几次才能确定您正在将 const 引用初始化为另一个指针的别名。
    【解决方案5】:

    扮演魔鬼的拥护者:除了明显的文档意图外,由于它是私有属性,因此您完全可以不使用const 关键字,并且除了init 方法之外不要修改它。

    你的const_cast 在这里实际上可能是未定义的行为,我当然不喜欢在那些黑暗的角落里奔跑,不管有什么变通方法。

    class EPWM {
    private:
       volatile EPWM_REGS* regs; // normally const, but need to be inited :/
    public:
       void init(volatile EPWM_REGS* _regs);
    };
    

    不过,重新审视您的问题:虽然不能默认构造 raw 数组,但您可以编写一个可以构造的数组类。

    namespace detail
    {
      template <class T, size_t N, size_t index>
      struct At
      {
        static T& Do(Array<T,N>& array)
        {
          return At<T,N-1,index-1>::Do(array.tail());
        }
      };
    
      template <class T, size_t N>
      struct At<T,N,0>
      {
        static T& Do(Array<T,N>& array) { return array[0]; }
      };
    
      template <class T, size_t index>
      struct At<T,0,index> {};
    
      template <class T>
      struct At<T,0,0> {};
    } // namespace detail
    
    
    template <class T, size_t N>
    class array
    {
    public:
      typedef T value_type;
      static const size_t Length = N;
    
      array(): mHead(), mTail() {}
      array(const array& rhs): mHead(rhs.mHead), mTail(rhs.mTail) {}
    
      // Don't know whether it will be optimized or not
      // Not sure I can use pointer arithmetic either :p
      T& operator[](size_t index) { return index == 0 ? mHead : mTail[index-1]; }
    
      // Compile time access
      template <size_t index>
      T& at() { return detail::At< T, N, index >::Do(*this); }
    
    private:
      T mHead;
      array<T, N-1> mTail;
    }; // class array<T,N>
    
    template <class T>
    class array<T,1>
    {
    public:
      typedef T value_type;
      static const size_t Length = 1;
    
      array(): mHead() {}
      array(const array& rhs): mHead(rhs.mHead) {}
    
      T& operator[](size_t index) { return mHead; } // or error handling ;)
    
    private:
      T mHead;
    }; // class array<T,1>
    
    template <class T> class array<T,0> {}; // int[0] does not work (stack) so...
    

    好吧...可能不如真正的数组高效...不过,您总是可以使用预处理器生成:

    template <class T>
    class Array4
    {
    public:
      Array4(): m0(), m1(), m2(), m3() {}
      Array4(const Array4& rhs): m0(rhs.m0), m1(rhs.m1), m2(rhs.m2), m3(rhs.m3) {}
    
      T& operator[](size_t index) { return *(&m0 + index); }
    
    private:
      T m0;
      T m1;
      T m2;
      T m3;
    }; // class Array4<T>
    

    【讨论】:

      猜你喜欢
      • 2015-06-10
      • 1970-01-01
      • 2011-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-02
      相关资源
      最近更新 更多