【问题标题】:Declaring a variable as a "Class" datatype, without calling the "Class" constructor?将变量声明为“类”数据类型,而不调用“类”构造函数?
【发布时间】:2010-01-31 09:32:02
【问题描述】:

如果我只是公然遗漏了什么,请原谅我,但我正在尝试从结构和 c 过渡到类和 c++。

这就是我想要做的:

A 有一个“Checkers”类和一个“Board”类。

现在有了结构,我可以在我的“board.cpp”文件中创建一个 Checkers 数组,方法是:

Checker checkers[2][12]

(每边0和1,每块0-11)

问题在于,对于类,执行相同的声明会尝试调用“Checkers”构造函数。我收到这个错误:“错误:没有匹配函数调用‘Checker::Checker()’”

我的 Checker 构造函数处理初始化一个单独的部分(比如它在 0 或 1 侧,0-11 部分),所以我不想在那里调用它。

有没有办法避免这种情况,或者我是不是走错了路?谢谢。

编辑:或者我应该只设计构造函数来初始化一个检查器数组?您甚至可以将变量声明为类/对象的数据类型吗?

【问题讨论】:

  • 另一种情况:“显然,我对问题的英文描述比发布编码要好”。邮政编码。用代码的上下文解释问题。

标签: c++ class constructor


【解决方案1】:

您可以创建一个默认构造函数或拥有一个Checker 指针数组,并通过在Board 的构造函数中使用适当的参数动态分配每个Checker 来初始化它们。在后一种情况下,在分配它们之前不会调用构造函数。

【讨论】:

    【解决方案2】:

    创建一个默认构造函数。然后使用初始函数。我建议你使用 STL 向量。

    【讨论】:

    • 那么,不要在Checkers构造函数中做任何事情,稍后再初始化值?
    • 以上建议都不好。默认构造函数不会解决问题,它会隐藏问题。它需要重新思考课堂的运作方式。向量适用于动态调整大小的数组,但大小在编译时是已知的(而不是动态分配的),因此没有理由使用向量。
    • 使用向量有一个原因——如果你的库实现了它,你就会得到边界检查。 (假设您不想导入任何其他边界检查数组类)。但否则是的。
    • 实际上向量(正常使用)NOT 有边界检查。您特别需要使用边界检查 API 'at(X)'。如果我们谈论的是调试模式,那么是的,向量可以有一个调试版本的 STL,它实现了边界检查,但编译器在这种情况下也可能对数组进行边界检查(如果可能的话)。
    • 我同意 Martin 的观点——C++ 的库中可能有一些高级功能,但在很多情况下它仍然具有低级脆弱性。对向量的越界访问的结果是官方未定义的,与数组没有什么不同 - 如果你有一些东西 more 而不是 C++,你只会得到一个异常抛出,你可以得到东西也可以对普通的 C 数组执行此操作(有一个产品 称为 Boundschecker)。顺便说一句 - 这包括基于迭代器的访问 - 在典型的 C++ 实现中,向量迭代器可以很好地移出向量的边界。
    【解决方案3】:

    问题在于,对于类,执行相同的声明会尝试调用“Checkers”构造函数。我收到此错误:“错误:没有匹配函数调用‘Checker::Checker()’”

    如果你为你的类定义了参数化构造函数(并且没有定义默认构造函数),编译器不会提供默认构造函数。您还必须编写默认构造函数的版本。

    不要使用二维数组,而是使用向量的向量。

    std::vector<std::vector<Checker> > checkers;
    

    【讨论】:

    • @Downvoter:请告诉我原因。这太不可思议了,两次无缘无故投了反对票。 x-(
    • +1 回到 0。看看好的一面,你获得了 (2 * 10) - (2 * 2) = 16 代表!
    • 不是我。但我试图再给你一个反对票。为什么要使用向量?数组的大小是静态的,不是动态分配的。不好的建议。编写默认构造函数不会解决问题(只是隐藏它)。
    • @Daniel:坦率地说,我不太关心声誉(我们都在这里学习),但我不明白为什么我的回答被否决了。答案没有那么糟糕
    • @Martin:大小在编译时是已知的,这很好。我只是推荐了我应该拥有的东西。数组是邪恶的,你最好知道它,就默认构造函数而言,如果他创建另一个没有参数的 Checker 对象怎么办?然后他必须定义它。:-)
    【解决方案4】:

    您正在创建一个检查器数组来表示属于每一侧的各个检查器。跳棋要求您说出跳棋在哪一侧,以及在哪一侧跳棋。

    为什么你需要知道哪个检查器是哪个?如果一个玩家走出房间,并且有人交换了他的两个棋子,他会注意到吗?

    您可以使用数组语法传递一个构造函数参数,如下所示:

    enum Side { White, Black };
    
    class Checker
    {
        Side side ;
    public:
        Checker ( Side side ) : side(side) {
        }
    };
    
    
    int main()
    {
        Checker white[12] = { White, White, White, White, White, White, White, White, White, White, White, White, };
        Checker black[12] = { Black, Black, Black, Black, Black, Black, Black, Black, Black, Black, Black, Black, };
        Checker* both[2] = { white, black };
    
        return 0;
    }
    

    多个参数需要一个复制构造函数,看起来像:

        Checker white[12] = { Checker(White,0), Checker(White,1) ...
    

    但我倾向于只使用几个棋子对象将棋子添加到棋盘中,而不是代表白、黑、白皇后和黑皇后,除非有很好的理由来跟踪身份。

    【讨论】:

    • 我对每个棋子都有单独的数字,因为这就是我显示棋盘并获取用户输入要移动的棋子的方式
    【解决方案5】:

    要回答这个问题,我真的需要看一下“Checker”类的定义。不过,这是一个猜测......

    我认为您的 Checker 类定义了非默认构造函数,但没有默认构造函数。有一个默认的默认构造函数 IYSWIM,但是一旦您为自己定义了任何构造函数,编译器提供的隐式默认构造函数就会被禁用。

    如果你有...

    class Checker
    {
      public:
        Checker (int p)  {  ...  };
    };
    

    您不能根据需要使用默认构造函数...

    Checker checkers[2][12];
    

    相反,尝试...

    class Checker
    {
      public:
        Checker ()  {  ...  };
        Checker (int p)  {  ...  };
    };
    

    关于使用 std::vector 的建议,在这种情况下我不同意。该数组是固定大小的,因此使用 std::vector 没有任何好处 - 只有额外的复杂性和其他成本。

    我的建议是保留您的 C 样式数组,但在“Board”类中将其设为私有(或至少受保护)。

    【讨论】:

      猜你喜欢
      • 2016-07-03
      • 1970-01-01
      • 2019-03-04
      • 2019-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-07
      相关资源
      最近更新 更多