简体   繁体   中英

pointer to class objects initialization with class constructor?

// pointer to classes example
// runs with no problem
#include <iostream>
using namespace std;

class Rectangle {
  int width, height;
public:
  Rectangle(int x, int y) : width(x), height(y) {}
  int area(void) { return width * height; }
};


int main() {
  Rectangle obj (3, 4);
  Rectangle * foo, * bar, * baz;
  foo = &obj;
  bar = new Rectangle (5, 6);
  baz = new Rectangle[2] { {2,5}, {3,6} };
  cout << "obj's area: " << obj.area() << '\n';
  cout << "*foo's area: " << foo->area() << '\n';
  cout << "*bar's area: " << bar->area() << '\n';
  cout << "baz[0]'s area:" << baz[0].area() << '\n';
  cout << "baz[1]'s area:" << baz[1].area() << '\n';       
  delete bar;
  delete[] baz;
  return 0;
}   

I am a bit (no pun intended) confused about this line of code here:

baz = new Rectangle[2] {{2,5}, {3,6}};

I've seen code like:

int *foo = new int[3] {1,2,3};

and I totally understand it. But what's the syntax of {{2,5}, {3,6}} here? How can array of class objects be initialized like this? I've searched many online c++ references but have no clue.

Just using initializer lists to populate both Rectangles in the array.

Think of:

{2,5}, {3,6}

As just calling Rectangle{2,5}, Rectangle{3,6}.

The Rectangle constructor takes two int . If you look at the line Rectangle obj (3, 4); This could also be Rectangle obj {3, 4};

(Note that this only applies to C++11 and later)

baz = new Rectangle[2] { {2,5}, {3,6} };

This syntax is called list-initialization .

List-initializing an aggregate such as an array results (unsurprisingly) in aggregate initialization , which will perform copy-initialization on each element; since the initializers here are lists themselves this results in copy-list-initialization .

When you list-initialize a (non-aggregate) class, the compiler looks up the constructors and selects the best match. You'll get an error at this point if the selected constructor requires a narrowing conversion of any of the arguments (such as double -> int ), or if it is an explicit constructor because copy-list-initialization is a form of copy-initialization ; only direct-initialization such as Rectangle r{2, 5}; can use explicit constructors (although narrowing conversions are still an error).

With C++11 it's possible to initialize an object instance with {x, y, z} . For example:

struct P2d {
    double x, y;
};

void foo(P2d p);

void bar() {
    foo({10, 20}); // Compiles fine
}

Using it for arrays is ok, and it's also ok for simple cases. In more complex cases it just increases the confusion as you're only see the values but you don't know what these values are used for.

It's like having API used like

 createWindow(0, 0, true, NULL, NULL, 1, NULL, false);

what are these values for?

Just don't overuse the new braces initialization... there are cases in which it's fantastic:

// C++03
std::vector<int> list_of_values() {
    std::vector<int> result;
    result.push_back(1);
    result.push_back(2);
    result.push_back(3);
    return result;
}

// C++11
std::vector<int> list_of_values() {
    return {1, 2, 3};
}

but there are cases in which just makes things worse:

{Rect(2, 3), Rect(4, 5)}

is actually more readable than

{{2, 3}, {4, 5}}

(remember that ease when reading code is much more important than ease when writing code... most lines of code are written once and read many times)

baz = new Rectangle[2] { {2,5}, {3,6} };

is not compilable.

Even,

int * abc = new int[3] {1,2,3} ;

is not compilable.

If you wan to create an array of Rectangle class with non-default constructor, do something like this:

  Rectangle baz[] = { Rectangle(2,5) ,  Rectangle(3,6) };

Please let me know if it is not clear.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM