0

我是一名高级 PHP/Perl 开发人员,也是 C++ 的相对初学者。

我拥有的是一个类的对象数组,其中一个元素又是子类的数组指针(如果我使用正确的术语)。我需要的是一个一个地处理主数组并将其元素提取到一个单独的位置,如果它们满足特定条件(唯一的 Name 属性)。然后输出提取一个及其子数组。然后输出原件。

我想出了各种解决方案,并试图在您的帮助下确定哪个是最好的。

细节。

这些是我提到的 2 个类的头文件的一部分:

/// class to define the modificable parameters of the machine
class CMachineParameter {
    public:
        /// Short name: "Cutoff"
        char const *Name;
        /// Longer description: "Cutoff Frequency (0-7f)"
        char const *Description;
        /// recommended >= 0. If negative, minValue is represented as 0 in the pattern
        int MinValue;
        /// recommended <= 65535. Basically so that it can be represented in the pattern
        int MaxValue;
        /// flags. (see below)
        int Flags;
        /// default value for params that have MPF_STATE flag set
        int DefValue;
};

///\name CMachineParameter flags
///\{
    /// shows a line with no text nor knob
    int const MPF_NULL = 0;
    /// shows a line with the text in a centered label
    int const MPF_LABEL = 1;
    /// shows a tweakable knob and text
    int const MPF_STATE = 2;
///\}

///\name CFxCallback::CallbackFunc codes
///\{
    int const CBID_GET_WINDOW = 0;
///\}
///\name CMachineInfo::HostEvent codes
///\{
    /// Sent by the host to ask if this plugin uses the auxiliary column. return true or false.
    int const HE_NEEDS_AUX_COLUMN = 0;
///\}

/*////////////////////////////////////////////////////////////////////////*/

/// class defining the machine properties
class CMachineInfo {
    public:
        CMachineInfo(
            short APIVersion, int flags, int numParameters, CMachineParameter const * const * parameters,
            char const * name, char const * shortName, char const * author, char const * command, int numCols
        ) :
            APIVersion(APIVersion), PlugVersion(0), Flags(flags), numParameters(numParameters), Parameters(parameters),
            Name(name), ShortName(shortName), Author(author), Command(command), numCols(numCols)
        {}

        CMachineInfo(
            short APIVersion, short PlugVersion, int flags, int numParameters, CMachineParameter const * const * parameters,
            char const * name, char const * shortName, char const * author, char const * command, int numCols
        ) :
            APIVersion(APIVersion), PlugVersion(PlugVersion), Flags(flags), numParameters(numParameters), Parameters(parameters),
            Name(name), ShortName(shortName), Author(author), Command(command), numCols(numCols)
        {}

        /// API version. Use MI_VERSION
        short const APIVersion;
        /// plug version. Your machine version. Shown in Hexadecimal.
        short const PlugVersion;
        /// Machine flags. Defines the type of machine
        int const Flags;
        /// number of parameters.
        int const numParameters;
        /// a pointer to an array of pointers to parameter infos
        CMachineParameter const * const * const Parameters;
        /// "Name of the machine in listing"
        char const * const Name;
        /// "Name of the machine in machine Display"
        char const * const ShortName;
        /// "Name of author"
        char const * const Author;
        /// "Text to show as custom command (see Command method)"
        char const * const Command;
        /// number of columns to display in the parameters' window
        int numCols;
};

这是我的代码:

for(int i(0) ; i < MAX_MACHINES ; ++i) if(song.machine(i)) {
    if (song.machine(i)->GetDllName() == "") continue;
    Plugin & plug = *((Plugin*)song.machine(i));
    const psycle::plugin_interface::CMachineInfo  psycle_info = plug.GetInfo();

    // Process machine general info: psycle_info.Name, psycle_info.ShortName, psycle_info.Author etc

    if(psycle_info.numParameters > 0 && psycle_info.Parameters) {
        const int n = psycle_info.numParameters;
        for(int i(0) ; i < n; ++i) {
            const psycle::plugin_interface::CMachineParameter & psycle_param(*psycle_info.Parameters[i]);

            // Process machine's parameters: psycle_param.MinValue, psycle_param.MaxValue, psycle_param.DefValue, psycle_param.Flags etc

基本上,我有一个虚拟机列表,每个虚拟机都有它的参数。只有 ShortName 不同(机器红色 1、机器红色 3、机器灰色 4)。我需要按名称输出唯一的机器及其参数(机器红色,机器灰色)。

在 PHP 中,我会简单地创建和数组,如 $original[psycle_info.Name] = array('author'=>psycle_info.Author, 'parameters'=>array(psycle_param.MinValue, psycle_param.MaxValue, psycle_param.DefValue, psycle_param.标志));

在 C++ 中,我发现我可以使用 std::map 和 std::vector STL 库实现类似的功能。这篇文章展示了一个非常相似的问题以及我从其他来源找到的解决方案: http ://www.dreamincode.net/forums/topic/67804-c-multidimensional-associative-arrays/

但是这样做的一般方法是什么?也许我需要创建 2 个新的非常量元素类?或者可能是一个简单的标准数组并一直使用标准数组循环函数?

非常感谢您的关注!

PS。数据示例:

0.
Name: 'Red Machine v.098'
ShortName: 'Red Machine 1'
Author: 'Jeremy'
Parameters: 0(Name: 'OSC type', MinValue: 0, MaxValue: 255, DefValue:0), 1(Name: 'CutOff', MinValue: 0, MaxValue: 16555, DefValue: 1000), 2(Name: 'LFO', MinValue: 100, MaxValue: 30555, DefValue: 3000)

1.
Name: 'Red Machine v.098'
ShortName: 'Red Machine 2'
Author: 'Jeremy'
Parameters: 0(Name: 'OSC type', MinValue: 0, MaxValue: 255, DefValue:0), 1(Name: 'CutOff', MinValue: 0, MaxValue: 16555, DefValue: 1000), 2(Name: 'LFO', MinValue: 100, MaxValue: 30555, DefValue: 3000)

2.
Name: 'Yellow Machine v.2.4.5'
ShortName: 'Yellow Machine 1'
Author: 'Anthony'
Parameters: 0(Name: 'OSC 1 wave', MinValue: 0, MaxValue: 255, DefValue: 0), 1(Name: 'OSC 2 Wave', MinValue: 0, MaxValue: 255, DefValue: 0), 2(Name: 'OSC 3 Wave', MinValue: 0, MaxValue: 255, DefValue: 0)

3.
Name: 'Yellow Machine v.2.4.5'
ShortName: 'Yellow Machine 2'
Author: 'Anthony'
Parameters: 0(Name: 'OSC 1 wave', MinValue: 0, MaxValue: 255, DefValue: 0), 1(Name: 'OSC 2 Wave', MinValue: 0, MaxValue: 255, DefValue: 0), 2(Name: 'OSC 3 Wave', MinValue: 0, MaxValue: 255, DefValue: 0)

显然,作为这种情况下的输出,我需要有 2 台独特的机器。

PS2。我现在将进一步描述我拥有什么以及需要做什么。

我有一个数组 song.machine(i)

算法:

  1. 由于 song.machine(i) 信息有限,循环通过它来获取另一个对象并对其进行操作
  2. 在循环中,从每个 song.machine(i) 创建 Plugin(类对象)插件,以便最终可以通过 psycle_info = plug.GetInfo(); 获取对象 CMachineInfo psycle_info;其中包含我们需要输出的所有信息
  3. 比较 psycle_info.Name 中的名称。如果已经显示,请跳到下一个。否则,输出数据。

这是我包含的头文件,其中包含我最初显示的 2 个类:http: //sourceforge.net/p/psycle/code/HEAD/tree/trunk/psycle-plugins/src/psycle/plugin_interface.hpp

再次总结一下:由于我只能迭代地访问对象,而且我需要对数据执行一些操作(比如将名称中的所有空格替换为“+”),我想到了创建一个临时数组/类。但可能,创建一个简单的数组 char nameShown[100] 就足够了,我可以在其中存储已经显示的所有名称,并且每次 song.machine(i) 迭代,循环遍历整个 nameShown,如果它包含当前名称,继续下一个。我只是不想每次都循环通过“nameShown”,在 PHP 中我们可以为此使用关联数组:所以我只能检查 ($nameShown[$Name]) 是否存在。就像你说的那样,我也很头疼,我不能复制属性和参数,因为它们是常量!看起来很简单的任务,但对于像我这样的初学者来说太难了。希望我

PS4。我刚刚还更新了主题的名称,因此它将包含“不断”提及。

PS5。这是基本上应该做我需要的代码:

std::string nameShown[100];
bool should_skip = false;
for (int k(0); k < i; k++) {
    if (nameShown[k] == psycle_info.Name) {
        should_skip = true;
    }
}
if(should_skip)  continue;
    nameShown[i] = psycle_info.Name;
std::ostringstream l; l << "Plugin: " << psycle_info.Name; loggers::warning()(l.str());

所以完整的部分看起来像:

std::string nameShown[100];
for(int i(0) ; i < MAX_MACHINES ; ++i) if(song.machine(i)) {
    if (song.machine(i)->GetDllName() == "") continue;
    Plugin & plug = *((Plugin*)song.machine(i));
    const psycle::plugin_interface::CMachineInfo  psycle_info = plug.GetInfo();

    // Process machine general info: psycle_info.Name, psycle_info.ShortName, psycle_info.Author etc
    bool should_skip = false;
    for (int k(0); k < i; k++) {
        if (nameShown[k] == psycle_info.Name) {
            should_skip = true;
        }
    }
    if(should_skip)  continue;
    nameShown[i] = psycle_info.Name;
    std::ostringstream l; l << "Plugin: " << psycle_info.Name; loggers::warning()(l.str());

    if(psycle_info.numParameters > 0 && psycle_info.Parameters) {
        const int n = psycle_info.numParameters;
        for(int i(0) ; i < n; ++i) {
            const psycle::plugin_interface::CMachineParameter & psycle_param(*psycle_info.Parameters[i]);

            // Process machine's parameters: psycle_param.MinValue, psycle_param.MaxValue, psycle_param.DefValue, psycle_param.Flags etc

循环插入前的输出:

log:  446322us: W: main: Plugin: Sublime 1.1
log:  446413us: W: main: Plugin: Pooplog FM UltraLight0.68b
log:  446497us: W: main: Plugin: Phantom 1.2
log:  446581us: W: main: Plugin: Pooplog FM UltraLight0.68b
log:  446649us: W: main: Plugin: FeedMe 1.2
log:  446729us: W: main: Plugin: Drum Synth v.2.5
log:  446793us: W: main: Plugin: Sublime 1.1
log:  446876us: W: main: Plugin: Arguru Compressor
log:  446945us: W: main: Plugin: Pooplog Filter 0.06b
log:  447016us: W: main: Plugin: Slicit
log:  447095us: W: main: Plugin: EQ-3
log:  447163us: W: main: Plugin: Arguru Compressor
log:  447231us: W: main: Plugin: Pooplog Filter 0.06b
log:  447294us: W: main: Plugin: Koruz
log:  447361us: W: main: Plugin: Pooplog Filter 0.06b
log:  447425us: W: main: Plugin: EQ-3
log:  447496us: W: main: Plugin: Arguru Compressor
log:  447558us: W: main: Plugin: EQ-3

后:

log:  414242us: W: main: Plugin: Sublime 1.1
log:  414331us: W: main: Plugin: Pooplog FM UltraLight0.68b
log:  414415us: W: main: Plugin: Phantom 1.2
log:  414499us: W: main: Plugin: FeedMe 1.2
log:  414560us: W: main: Plugin: Drum Synth v.2.5
log:  414622us: W: main: Plugin: Arguru Compressor
log:  414694us: W: main: Plugin: Pooplog Filter 0.06b
log:  414761us: W: main: Plugin: Slicit
log:  414830us: W: main: Plugin: EQ-3
log:  414897us: W: main: Plugin: Koruz

请注意,在新添加的循环中,我尝试使用 for (int k(0); k < sizeof(nameShown); k++) 对于 PHP 程序员来说这听起来更明显,但即使是在第一首 song.machine (i) 迭代,它自己循环了很多次,然后给出一个段错误,所以我把它改成了“k < i”。

这基本上就是我所需要的。并且只是好奇它是否是正确的做法,因为每次循环通过过滤器数组的不存在元素对我来说听起来很原始且无效。

另一件事是,在我刚刚完成的独特机器的输出之后,我需要输出整个列表。那又怎样,我必须再次创建整个 song.machine(i) 循环,所以为了避免代码重复,我想到了将我需要的值提取到更简单的数据句柄中。在 PHP 中,我会为此使用关联数组。

再次总结一下,首先我需要输出唯一的机器列表,然后为每个列表设置不同的详细信息。

可能,因为解释起来似乎很复杂(但实际上这是一个非常简单的任务,XML 生成)我会坚持什么是有效的,在这种情况下寻找最好的代码可能太奢侈了。

4

1 回答 1

0

让我们从清楚的开始,你有一个数组 song.machine(i)

算法:

  1. 比较 song.machine(i) 中的名称
  2. 如果匹配,则将 song.machine(i) 动态转换为 Plugin(类对象)插件
  3. 使用它通过 psycle_info = plug.GetInfo(); 创建对象 CMachineInfo psycle_info
  4. 处理这些数据/输出/提取它?.

让我们从您在类定义中编写的内容开始:

  • 字符*

    一个 char*,声明在堆/堆栈上分配内存。随着对象在应用程序中被销毁,这又必须被删除。您的代码正在创建大量对象,然后您复制它们,将它们传递给另一个对象。未分配指针的内存位置(例如 new [] 运算符/malloc),最终将被任何类型/对象数据覆盖。有时您可能不会遇到分段错误,但在这种情况下您的数据肯定不安全。

    在这种情况下,您应该使用string、内置 char* 或 char 数组。他们自行分配和销毁。因此不会出现内存错误,而且 string.compare() 等函数也很容易使用。参考这里

  • 复制/赋值运算符

    复制和赋值运算符(例如 CMachineInfo obj1 = CMachineInfo Obj2)作用于类的对象,顾名思义,它们旨在在对象之间传递数据。C++ 默认为您定义运算符。但是当您处理指针时,这种行为很棘手。您可以通过定义您想要的内容来覆盖它(见下文)。

  • 成员

    在 c++ 类中,成员可以是具有规则的 const(没有变通的整数),具有 const 成员的对象不能在 COPY AND ASSIGNMENT OPERATOR 中使用。这很容易理解。您有一个对象 obj1,现在您想将其所有内容复制到另一个对象 obj2(同一个类)。创建 Obj2 时,它的成员被定义为常量,现在您正试图覆盖这些值。编译器不允许这样做。解决此类问题的方法是将此类成员声明为private。不允许私人成员直接访问(例如 pyscle_info.Name)。您必须编写一个公共函数,该函数反过来可以向他们提供这种访问权限(例如 pyscle_info.GET_NAME_OF_MACHINE();)

再来看看修改后的代码CMachineParameter:

class CMachineParameter{

public:

    CMachineParameter(string Name, string Description, int MinValue, 
                        int MaxValue, int Flags, int DefValue
    ): Name(Name), Description(Description), MinValue(MinValue), MaxValue(MaxValue), Flags(Flags), DefValue(DefValue)
    {}

    /*DeFault Constructor*/
    CMachineParameter(): Name("TEST"), Description("Temp Object")
    {}

    //  Copy Constructor
    CMachineParameter(const CMachineParameter &TO_BE_COPIED)
    : Name(TO_BE_COPIED.Name), Description(TO_BE_COPIED.Description), MinValue(TO_BE_COPIED.MinValue),
      MaxValue(TO_BE_COPIED.MaxValue) ,Flags(TO_BE_COPIED.Flags), DefValue(TO_BE_COPIED.DefValue)
    {}

    //  Assignment Operator
    CMachineParameter & operator=(const CMachineParameter & TO_BE_Assigned)
    {
        if(this != &TO_BE_Assigned)
        {
            Name        = TO_BE_Assigned.Name;
            Description = TO_BE_Assigned.Description;
            MinValue    = TO_BE_Assigned.MinValue;
            MaxValue    = TO_BE_Assigned.MaxValue;
            Flags       = TO_BE_Assigned.Flags;
            DefValue    = TO_BE_Assigned.DefValue;
        }

        return *this;
    }

    void show(void) const;

    /*To access the Private members*/
    std::string GET_NAME(void) const;

    /// recommended >= 0. If negative, minValue is represented as 0 in the pattern
    int MinValue;
    /// recommended <= 65535. Basically so that it can be represented in the pattern
    int MaxValue;
    /// flags. (see below)
    int Flags;
    /// default value for params that have MPF_STATE flag set
    int DefValue;

private:
    /*
     * Making them as Private as Assignment and copy operator Cannot be used with Const members.
    */
    /// Short name: "Cutoff"
    string Name;
    /// Longer description: "Cutoff Frequency (0-7f)"
    string Description;
};

void CMachineParameter::show() const
{
    cout << "------------------------------------------------------\n";
    cout << "My Machine " << Name << endl
         << "\t" << Description << endl
         << "\tMinValue:    " << MinValue << endl
         << "\tMaxValue:    " << MaxValue << endl
         << "\tFlags:       " << Flags << endl
         << "\tDefValue:    " << DefValue << endl;
    cout << "------------------------------------------------------\n";
}

std::string CMachineParameter::GET_NAME(void) const
{
    return Name;
}

对于 CMachineInfo,您需要实现分配/复制运算符。我实现了一个 CMachineParameter const * 的向量。

class CMachineInfo {
    public:
        CMachineInfo(
            short APIVersion, int flags, int numParameters,
            string name, string shortName, string author, string command, int numCols
        ) :
            APIVersion(APIVersion), PlugVersion(0), Flags(flags), numParameters(numParameters),
            Name(name), ShortName(shortName), Author(author), Command(command), numCols(numCols)
        {}

        CMachineInfo(
            short APIVersion, short PlugVersion, int flags, int numParameters,
            string name, string shortName, string author, string command, int numCols
        ) :
            APIVersion(APIVersion), PlugVersion(PlugVersion), Flags(flags), numParameters(numParameters),
            Name(name), ShortName(shortName), Author(author), Command(command), numCols(numCols)
        {}

        //  Copy Constructor
        CMachineInfo (const CMachineInfo &TO_BE_COPIED)
        : APIVersion(TO_BE_COPIED.APIVersion), PlugVersion(TO_BE_COPIED.PlugVersion),
        Flags(TO_BE_COPIED.Flags), numParameters(TO_BE_COPIED.numParameters), Name(TO_BE_COPIED.Name),
        ShortName(TO_BE_COPIED.ShortName), Author(TO_BE_COPIED.Author), Command(TO_BE_COPIED.Command),
        numCols(TO_BE_COPIED.numCols), Parameter(TO_BE_COPIED.Parameter)
        {}

        //  Assignment Operator
        CMachineInfo & operator=(const CMachineInfo &TO_BE_Assigned)
        {
            if(this != &TO_BE_Assigned)
            {
                APIVersion      = TO_BE_Assigned.APIVersion; 
                PlugVersion     = TO_BE_Assigned.PlugVersion;
                Flags           = TO_BE_Assigned.Flags;
                numParameters   = TO_BE_Assigned.numParameters; 
                Name            = TO_BE_Assigned.Name;
                ShortName       = TO_BE_Assigned.ShortName; 
                Author          = TO_BE_Assigned.Author; 
                Command         = TO_BE_Assigned.Command;
                numCols         = TO_BE_Assigned.numCols;
                Parameter       = TO_BE_Assigned.Parameter;
            }
            return *this;
        }

        void SHOW(void) const;

        /// a pointer to an array of pointers to parameter infos
        /// CMachineParameter const * const * const Parameters;
        vector<CMachineParameter const *> Parameter;

        /// "Name of the machine in listing"
        std::string Name;

        /// "Name of the machine in machine Display"
        std::string ShortName;

        /// "Name of author"
        std::string Author;

        /// "Text to show as custom command (see Command method)"
        std::string Command;

        /// number of columns to display in the parameters' window
        int numCols;

private:
        /// API version. Use MI_VERSION
        short APIVersion;

        /// plug version. Your machine version. Shown in Hexadecimal.
        short PlugVersion;

        /// Machine flags. Defines the type of machine
        int Flags;

        /// number of parameters.
        int numParameters;
};

void CMachineInfo::SHOW() const
{
    cout << "My Machine IS: " << endl
         << "\tAPIVersion:    " << APIVersion << endl
         << "\tPlugVersion:   " << PlugVersion << endl
         << "\tFlags:         " << Flags << endl
         << "\tnumParameters: " << numParameters << endl
         << "\tName:          " << Name << endl
         << "\tShortName:     " << ShortName << endl
         << "\tAuthor:        " << Author << endl
         << "\tCommand:       " << Command << endl
         << "\tnumCols:       " << numCols << endl;
}
于 2013-04-13T14:20:57.197 回答