类包含指向基类的指针,但我不希望它。(C++)
Class contains pointer to base class but I don't want it to. (C++)
一个奇怪的问题标题,但我不知道该如何紧凑地描述情况。
最近,我一直在问有关制作音频合成软件的问题。这个问题是关于特定问题的问题。我有。我的代码编译和工作正常;它只是"有点奇怪"如果愿意的话。
我有一个包含指向基类的指针。我将详细说明一个最小的示例,以详细说明发生了什么。
class SynthNoteBase
{
// example content
virtual
double Sample() = 0;
}; // just for base class pointer
class SynthNoteA : public SynthNoteBase
{
};
class SynthNoteB : public SynthNoteBase
{
}; // define two different types of note -
// these will synthesize different sounds
每个类SynthNote*
都有一个成员,例如Play()
或Sample()
,它将样本返回"播放"//quot"在音频文件中记录为"/&quot"。
现在,我有一个Synthesizer
对象(类),其中包含许多SynthesizerKey
对象。每个SynthesizerKey
类都包含一个指向基类SynthNoteBase
的指针。
说明:"Synthesizer
&quot就像真正的合成器一样,有许多不同的Key
S。这些Key
对象将具有Play()
方法或类似方法。主程序可以从输入源(键盘/文件)读取数据,并确定要播放的Key
s。每个键可能想要不同的声音。(至少,一个人将需要不同的音符频率。该频率将是SynthNote*
内的参数。)
到目前为止,一切都很好,除非构造SynthesizerKey
对象。
class SynthesizerKey
{
protected:
SynthNoteBase *m_synthnotebase_ptr;
public:
SynthesizerKey(SynthNoteBase* const synthnote)
: m_synthnotebase_ptr{synthnote}
{
}
virtual
~SynthesizerKey()
{
delete m_synthnotebase_ptr; // could be a problem
}
void Play()
{
m_synthnotebase_ptr->Play(); // or whatever
}
}
"问题"调用构造函数时发生。
SynthesizerKey key1(new SynthNoteA(...parameters...)); // had to use new here
// but we never delete! (delete hidden in destructor)
我感谢这并不是"问题"。per-se,但它确实产生了一些非常可怕的代码,其中最终用户正在用构造函数调用中的新内存分配内存,但似乎从未删除上述内存。
我的问题很清楚吗?这种情况有什么选择?
也许可以使用智能指针来解决这?我怀疑这确实是一个部分分辨率,因为我们可以使用智能指针隐藏"新"。部分以及"删除"部分...实际上不确定更好。
这是什么想法?
编辑1
(响应以下答案。)
我尝试了此解决方案:
class SynthesizerKey
{
std::unique_ptr<SynthNoteBase> m_note;
SynthesizerKey(const SynthNoteBase& note)
: m_note(new ...) // ah: can't do this!
// don't know what type to allocate with new?
{
}
}
但我不能分配内存,因为我将为基类类型分配存储而不是派生类型。
多态性的多态性工作您真的别无选择,只能使用指针。
至少对 hide 的可能的"解决方案"可能是将对基本对象作为参数作为参数的常数引用到SynthesizerKey
构造函数,并处理SynthesizerKey
构造函数初始化器列表中的内存分配和依靠"虚拟构造函数"(或克隆)模式复制对象。
另外,我建议您使用std::unique_ptr
而不是使用" RAW"指针。那么至少您不必担心删除对象。
在您的情况下,"虚拟构造函数"(或克隆)模式将是这样的:
class SynthNoteBase
{
// example content
virtual
double Sample() = 0;
virtual SynthNoteBase* clone() = 0;
};
class SynthNoteA : public SynthNoteBase
{
SynthNoteBase* clone()
{
return new SynthNoteA(*this); // Allocates and invokes the copy-constructor
}
};
class SynthNoteB : public SynthNoteBase
{
SynthNoteBase* clone()
{
return new SynthNoteB(*this); // Allocates and invokes the copy-constructor
}
};
class SynthesizerKey
{
std::unique_ptr<SynthNoteBase> m_note;
SynthesizerKey(const SynthNoteBase& note)
: m_note(note.clone()) // Clone the note, invokes copy-constructor correctly
{
}
};
如果这样做,请确保将Base
class'destructor Virtual也要!
如果您通过Base *
删除,则要确保派生的破坏者首先称为!
您对您要输入的内容的长度/措辞的"非常糟糕"的评论?如果是这样,我看不到您将如何解决:您需要所需的东西。
如果这是一种风格上的东西("有new
,delete
在哪里?"),请为这样做的知识感到安慰:
Minder(new Child());
意味着您显然"投降" Minder
的指针来照顾 - 现在是它的问题!
您基本上有三个选项:整个对象,参考对象和指向对象。
全目标:将对对象的引用传递到构造函数中,拿一个本地副本,然后将传递的副本破坏。
这里的问题是您不知道传递对象的类型,只是它是
Base
,因此任何Base
复制都将是原始的"切片" - 失去虚拟度。另外:纯种方法可防止整个Base
对象。参考对象:如果仅记得参考,那么您就放弃了管理上述对象的内存的选项。
you 可以做一个
delete &reference;
-但您最好还是保留了一个指针。指针对象:这是您的解决方案,我看不到任何错误。
我不相信您应该使用smartptr
-重点是什么?指针仅在一个地方;它是唯一可以访问的地方;破坏者将进入delete
IT;解决问题。
使用 smartptr
,而对象在对象的寿命中尚不清楚对象的所有权。它经过了很多。制作副本;那么该对象什么时候最终完成?在这里,物体的寿命是完全众所周知的,并在创建时间拥有一份所有权。不要使它复杂化。
虚拟构造函数是一个解决方案 - 以每个派生类中的 Clone()
方法为代价。您仍然需要构造派生的对象来传递它 - 让其他人只采用 Clone()
才能立即破坏它似乎是一项艰巨的努力。
您可以将注释成员表示为std :: unique_ptr,并通过值或引用synthesizerkey的构造函数(
)传递注释(从synthnotebase)传递。#include <memory>
#include <iostream>
class SynthNoteBase
{
public:
virtual ~SynthNoteBase() {}
virtual void Play() const = 0;
};
class SynthNoteA : public SynthNoteBase
{
public:
void Play() const override { std::cout << "Play An"; };
};
class SynthesizerKey
{
protected:
std::unique_ptr<SynthNoteBase> m_synthnotebase_ptr;
public:
template <typename Note>
SynthesizerKey(Note&& note)
: m_synthnotebase_ptr{
std::make_unique<typename std::decay<Note>::type>(
std::forward<Note>(note))}
{}
void Play() const { m_synthnotebase_ptr->Play(); }
};
int main()
{
SynthesizerKey keyA{SynthNoteA()};
keyA.Play();
return 0;
}
- 如何指定我希望我的LIB链接到的DLL文件?-Visual Studio 2019
- 我希望定义两个具有相同代码的不同名称的库
- 我希望改进或要求我目前的延迟/睡眠方法。C++
- 视觉我希望一个函数在另一个函数C++中进行计算
- 如果第一个元素包含任何零,则我的程序以不希望的方式运行
- 是否可以/希望创建不可复制的共享指针模拟(以启用weak_ptr跟踪/借用类型语义)?
- 如何在 c++ 中将密码和用户名保存到 .txt 文件中.如果用户尝试登录,我仍然希望能够检索它们
- 这个编译器错误究竟希望我执行什么?
- 为什么这个涉及 std::enable_if 的模板元函数会产生不希望的结果?
- 当我希望 1 时,c ++ int 会变为大约 4198321
- 我想使用 C++ 从 excel 获取记录,并希望使用特定的列数据(例如书籍 ID)控制输出
- 精灵不显示我希望它们显示的方式
- Clang希望我写:: STD :: Declval而不是STD :: Declval
- 当您希望在Arduino Uno编程中同时执行不同函数时,使用什么代码/语句
- 告诉编译器我希望变量始终存储在寄存器中的正确方法是什么
- 即使有例外,希望程序继续继续
- 我什么时候不希望在Visual Studio中启用“Control Flow Guard Microsoft
- 此功能希望从std :: istream解析该功能的输入格式
- 我希望通过使用模板元编程从变量ARGS中进行剥离参数
- 我希望在字符串功能上提供一些帮助