提问人:LastHerd 提问时间:6/28/2022 最后编辑:LastHerd 更新时间:6/28/2022 访问量:150
如何在父类内但在另一个头文件中创建嵌套类的对象?
How can I create objects of a nested class inside the parent class but in another header file?
问:
我有一个带有嵌套类的类。因此,在我的文件中有这些类之前,我只是在类中创建了一个对象数组,并且它工作正常。Dmx
touchSlider
main.cpp
touchSlider
Dmx
我怎样才能在这里实现这一点,使用不同的头文件?编译器给出错误消息: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)};
答:
为了创建数组,编译器需要类的定义。所以正如所写的那样,这是行不通的。touchSlider
touchSlider
在给定的代码中
touchSlider slider[10] = {50,130,210,290,370,50,130,210,290,370};
编译器需要知道对象有多大,以便为对象分配足够的内存。它还需要知道 a 可以从 .这两件事都需要 的完整定义。touchSlider
Dmx
touchSlider
int
touchSlider
现在,也许您可以使用一些变体来实现您的目标,但是如果没有更多细节,就很难提出任何建议。
评论
slider
touchSlider
为了能够创建数组:
touchSlider slider[10] = {50,130,210,290,370,50,130,210,290,370};
您需要可用的类定义,因为编译器需要知道
- 正在使用的结构体或类的大小,以及
- 如果有合适的构造函数可用。
现在有两个选项,要么在标头中提供类定义,要么在源文件中实现类,如下所示:
// 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
评论
Dxm::touchSlider