Bit*_*g3r 2 c++ constructor multidimensional-array
How do you declare and create a 2-dimensional array whose dimensions are constant and known at compile time, but are specified by literal const arguments to the constructor of the class that owns it?
For example...
class Foo {
public:
Foo(int rows, int cols);
private:
int totalRows;
int totalCols;
char buf[4][20]; // I don't actually WANT to hardcode 4 and 20 here!
};
Run Code Online (Sandbox Code Playgroud)
Foo::Foo(const int rows, const int cols) : totalRows(rows), totalCols(cols), buf(new char[rows][cols]) {}
Run Code Online (Sandbox Code Playgroud)
Foo myFoo(4,20);
Run Code Online (Sandbox Code Playgroud)
I know buf(char[rows][cols]) is totally wrong... it's just there to illustrate what I'm trying to achieve.
I'm pretty sure I somehow have to use constructor-initialization syntax (like I'm using to set the values of totalRows and totalCols) ... but, for arrays, I'm not sure what that syntax actually is. I'm not sure whether such syntax even exists for array-declaration, since the use case of "constructor with const int args that can only be invoked with literals to guarantee the values are known at compile-time and thus suitable for an array declaration" is admittedly kind of an extreme edge case.
In Java, I'd just declare a char[] named buf whose value is implicitly unassigned at declaration-time, then create (and assign) it in the body of the constructor ... but, as far as I know, C++ doesn't allow that, either.
I know I could probably sidestep the issue by making buf a char* and creating it in the constructor via malloc(rows * cols) ... but that seems kind of barbaric and just seems "bad" for some reason I can't quite put my finger on.
OK, it looks like @Adrian Mole's idea of using templates is the right one, but now I have a new problem... because Foo is now a Foo<4,20>, the compiler won't allow me to specify Foo or Foo* as a method or constructor parameter type... it wants them all to be explicitly specified, too.
The above notwithstanding, I just discovered that Foo.cpp now has an even bigger problem. When I try implementing Foo's other methods (which I suppose I should have mentioned), the compiler is rejecting them because "Foo is not a class, namespace, or declaration". For example, the following line now gets rejected:
int Foo::getTotalRows() {
return totalRows;
}
Run Code Online (Sandbox Code Playgroud)
... presumably, because there's no longer a class Foo. Except, it looks like I can't even temporarily hack around that by inserting <4,20> (eg, int Foo<4,20>::getTotalRows()).
Foo<4,20> myFoo;
Bar firstBar = new Bar(&myFoo, 2,17,4);
Run Code Online (Sandbox Code Playgroud)
class Bar {
public:
Bar(Foo<4,20>* srcFoo, int row, int col, int len);
// ... snip ...
private:
char* chars;
int length;
}
Run Code Online (Sandbox Code Playgroud)
{
Bar::Bar(Foo<4,20>* srcFoo, int row, int startCol, int length)
: chars(*srcFoo->getBuf(row, startcol, length), length(length) {}
// ... snip ...
}
Run Code Online (Sandbox Code Playgroud)
... which kind of defeats the point, because it means I've gone from having to hardcode the 4 and 20 in one place, to having to hardcode it in every single place I subsequently make use of a Foo object.
除非......有一种方法可以向编译器指示方法/构造函数应该与模板化类的任何变体相匹配,并且让编译器在编译时简单地自动生成特定的风格。例如,类似...
Bar(Foo<>* pFoo, int row, int col, int len);
Run Code Online (Sandbox Code Playgroud)
...这样如果Main.cpp执行类似以下操作:
Foo<4,20> myFoo;
Bar first(&myFoo,1,17,3);
Run Code Online (Sandbox Code Playgroud)
...编译器会说,“好吧,我知道 myFoo 是 Foo<4,20>,并且他正在调用 Bar 的构造函数。Bar 的构造函数采用 Foo<> 的任何风格,所以我就假装他声明了它在源中为:
Bar(Foo<4,20>* pFoo, int row, int col, int len);
Run Code Online (Sandbox Code Playgroud)
...并正常继续。然后,更进一步,如果我这样做:
Foo<2,16> smallerFoo;
Bar second(&smallerFoo, 0,3,11);
Run Code Online (Sandbox Code Playgroud)
...编译器会说,“好吧,smallerFoo 是一个Foo<2,16>.Bar的Foo*构造函数匹配,但由于我们还没有使用 a Foo<2,16>,所以我必须自动生成另一组方法并假装源代码确实说了类似的话:
Bar(Foo<4,20>* pFoo, int row, int col, int len);
Bar(Foo<2,16>* pFoo, int row, int col, int len);
Run Code Online (Sandbox Code Playgroud)
换句话说,让编译器也递归地将模板应用到自动生成匹配方法。
是否存在这样的东西,或者我必须回到绘图板,除非我想在每次后续使用 Foo 对象(包括方法参数)时显式指定 <rows,cols> ?
您可以创建Foo一个类模板,然后编译器将为所使用的rows和的每个不同组合创建一个单独的类。cols这将避免在构造函数中进行任何初始化(对于您概述的简单类),因为所有数据成员都可以默认初始化为其所需的值。
您的明显区别是,您将使用 \xe2\x80\xa6 ,main而不是使用像 这样的语法来声明和初始化,它将创建为名为 (类似) 的类的对象。Foo myFoo(4, 20);Foo<4, 20> myFoomyFooFoo<4,20>
这是一个简短的概述,其中包括一些示例成员函数以及如何为此类模板声明/定义它们:
\n#include <iostream>\n\ntemplate<int rows, int cols>\nclass Foo {\npublic:\n Foo() = default;\n void Init();\n void List();\nprivate:\n int totalRows{ rows };\n int totalCols{ cols };\n char buf[rows][cols]{};\n};\n\ntemplate<int rows, int cols>\nvoid Foo<rows, cols>::Init()\n{\n char i = 0;\n for (int r = 0; r < rows; ++r) {\n for (int c = 0; c < cols; ++c) {\n buf[r][c] = i++;\n }\n }\n}\n\ntemplate<int rows, int cols>\nvoid Foo<rows, cols>::List()\n{\n for (int r = 0; r < rows; ++r) {\n for (int c = 0; c < cols; ++c) {\n std::cout << static_cast<int>(buf[r][c]) << " ";\n }\n std::cout << std::endl;\n }\n}\n\nint main()\n{\n Foo<4, 20> myFoo;\n myFoo.Init();\n myFoo.List();\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
137 次 |
| 最近记录: |