如何在父类内但在另一个头文件中创建嵌套类的对象?

How can I create objects of a nested class inside the parent class but in another header file?

提问人:LastHerd 提问时间:6/28/2022 最后编辑:LastHerd 更新时间:6/28/2022 访问量:150

问:

我有一个带有嵌套类的类。因此,在我的文件中有这些类之前,我只是在类中创建了一个对象数组,并且它工作正常。DmxtouchSlidermain.cpptouchSliderDmx

我怎样才能在这里实现这一点,使用不同的头文件?编译器给出错误消息:invalid use of incomplete type 'class Dmx::touchSlider'

对象数组为:touchSlider slider[10] = {50,130,210,290,370,50,130,210,290,370};

dmx.h

// dmx.h

#ifndef dmx_h
#define dmx_h

class Dmx {
  public:
    byte number;                                                

    Dmx(byte numberA) {                                                 
      number = numberA;
    }

    void settingsDisplay();
    
    class touchSlider;             // declaration of nested class

    touchSlider slider[10] = {50,130,210,290,370,50,130,210,290,370};  
};

#endif

touchSlider.h

// touchSlider.h

#ifndef touchSlider_h
#define touchSlider_h

#include "dmx.h"

class Dmx::touchSlider{
  private:
  int pos;                                     

  public:
  touchSlider(int posA){                        
    pos = posA;                      
  }

  void printChannel();

};

#endif

主 .cpp

// main.cpp

#include "dmx.h"                
#include "touchSlider.h"

Dmx dmx[10] = {Dmx(1), Dmx(2),Dmx(3), Dmx(4), Dmx(5), Dmx(6), Dmx(7), Dmx(8), Dmx(9), Dmx(10)}; 


void Dmx::settingsDisplay() {
    // do something
}

void Dmx::touchSlider::printChannel() {
    // do something
}

我以前的代码(效果很好),其中两个类在同一个文件中看起来像这样:

class Dmx {
  public:
    byte number;                                                

    Dmx(byte numberA) {                                                 
      number = numberA;
    }

    void channelDisplay(){
    }                                            

    void settingsDisplay(){
    }
    
    class touchSlider{
    private:
      int pos;                                     

    public:
      touchSlider(int posA){                        
         pos = posA;                      
      }

      void setChannel(/* some arguments*/){
      }

      void printChannel();
      }
   };             

    touchSlider slider[10] = {50,130,210,290,370,50,130,210,290,370};        
};
Dmx dmx[10] = {Dmx(1), Dmx(2),Dmx(3), Dmx(4), Dmx(5), Dmx(6), Dmx(7), Dmx(8), Dmx(9), Dmx(10)}; 
嵌套的 C++ 对象

评论

0赞 paolo 6/28/2022
为什么要在不同的头文件中实现?为什么不在dxm.h中定义它并在dxm.cpp中实现它?Dxm::touchSlider
0赞 SoronelHaetir 6/28/2022
可以将 touchSlider 声明为 Dmx 的一部分,然后在 Dmx 外部定义 touchSlider,但不可能在 Dmx 中拥有 touchSlider 对象的数组(可以使用指向数组的指针)。
0赞 LastHerd 6/28/2022
@paolo我的想法是,这样它更干净。但也许我错了,我认为如果我将两者都放在同一个头文件中会更容易

答:

1赞 john 6/28/2022 #1

为了创建数组,编译器需要类的定义。所以正如所写的那样,这是行不通的。touchSlidertouchSlider

在给定的代码中

touchSlider slider[10] = {50,130,210,290,370,50,130,210,290,370};

编译器需要知道对象有多大,以便为对象分配足够的内存。它还需要知道 a 可以从 .这两件事都需要 的完整定义。touchSliderDmxtouchSliderinttouchSlider

现在,也许您可以使用一些变体来实现您的目标,但是如果没有更多细节,就很难提出任何建议。

评论

0赞 LastHerd 6/28/2022
所以最简单的方法是将嵌套类和父类放入一个头文件中,对吗?@john
0赞 john 6/28/2022
@LastHerd 你必须做更多的事情。如果你想成为一个数组,那么我看不出有任何替代方法。slidertouchSlider
2赞 Aconcagua 6/28/2022 #2

为了能够创建数组:

touchSlider slider[10] = {50,130,210,290,370,50,130,210,290,370};

您需要可用的类定义,因为编译器需要知道

  1. 正在使用的结构体或类的大小,以及
  2. 如果有合适的构造函数可用。

现在有两个选项,要么在标头中提供类定义,要么在源文件中实现类,如下所示:

// header:

class Dmx
{
public:
    // ...

    class TouchSlider
    {
    public:
        // only DECLARE here:
        TouchSlider(int posA);
        void setChannel(/* some arguments*/);
        void printChannel();
    };
};

// source:

Dmx::TouchSlider::TouchSlider(int posA)
    : pos(posA) // note: prefer the initialiser list!
{ }

void Dmx::TouchSlider::setChannel(/* some arguments*/)
{
}

// ...

或者你按照你的意图隐藏了实现,但随后你需要动态分配内存(这是 PImpl 的习惯用语)——充其量是借助:std::unique_ptr

class Dmx
{
public:
    // ...
private:
    class TouchSlider; // just declare

    std::unique_ptr<TouchSlider[]> sliders;
};

不过,重要(参见 cppreference):

std::unique_ptr可以为不完整的 T 类型构造,例如便于 pImpl 成语中用作句柄。如果使用默认删除器,则 T 必须在代码中调用删除器的点处完成,这发生在析构函数、移动赋值运算符和 的重置成员函数中。std::unique_ptr

也就是说,您也不能在头文件中实现您的类的析构函数,但也需要在源文件中这样做——在嵌套类的完整定义之后——就像任何可能重新分配另一个数组的函数一样。

避免了手动内存管理的必要性(参见/的规则),另一方面,该类变得不可复制(但您可以通过提供自己的自定义复制构造函数和赋值来解决,同时默认移动构造函数和赋值)。std::unique_ptr