将变量声明为“类”数据类型,而不调用“类”构造函数?

Posted

技术标签:

【中文标题】将变量声明为“类”数据类型,而不调用“类”构造函数?【英文标题】: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 部分),所以我不想在那里调用它。

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

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

【问题讨论】:

另一种情况:“显然,我对问题的英文描述比发布编码要好”。邮政编码。用代码的上下文解释问题。 【参考方案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”类中将其设为私有(或至少受保护)。

【讨论】:

以上是关于将变量声明为“类”数据类型,而不调用“类”构造函数?的主要内容,如果未能解决你的问题,请参考以下文章

单例模式

第十二章 类和动态内存分配

构造函数用于创建类的实例对象,构造函数名应与类名相同,返回类型为void.

PHP的抽象类接口的区别和选择

接口和抽象类

第四章总结