我有两个类,在示例中添加了Rectangle和Rectangles。目标是创建一个Rectangles对象,该对象保存对多个Rectangle对象的引用。
如果我按r
更改r.set_values(4,4)
,则会更改粗略r.area()
。但是,如果我拨打rectangles.rects[0].area()
,它仍为12,因此不会更改。
据我所知,我在r
中引用了rectangles
,但这似乎是错误的。
如何实现这一目标?
代码可用here
#include <iostream>
using namespace std;
class Rectangle {
int width, height;
public:
void set_values (int,int);
int area() {return width*height;}
};
void Rectangle::set_values (int x, int y) {
width = x;
height = y;
}
class Rectangles {
public:
Rectangles(int n);
void addRectangle(Rectangle* r);
Rectangle* rects;
int nRects;
};
Rectangles::Rectangles(int n) {
rects = new Rectangle[n];
nRects = 0;
}
void Rectangles::addRectangle(Rectangle* r) {
rects[nRects] = *r;
nRects++;
}
int main() {
Rectangle r;
Rectangles rectangles(5);
r.set_values(4,3);
rectangles.addRectangle(&r);
cout<<"r.area() before change:"<<r.area()<<endl;
cout<<"rectangles.rects[0].area() before change:"<<rectangles.rects[0].area()<<endl;
r.set_values(4,4);
cout<<"r.area() after change:"<<r.area()<<endl;
cout<<"rectangles.rects[0].area() after change:"<<rectangles.rects[0].area()<<endl;
return 0;
}
输出:
r.area() before change:12
rectangles.rects[0].area() before change:12
r.area() after change:16
rectangles.rects[0].area() after change:12
答案 0 :(得分:1)
class Rectangles {
public:
void addRectangle(Rectangle* r);
vector<Rectangle *> rects;
};
void Rectangles::addRectangle(Rectangle* r) {
rects.push_back(r);
}
int main() {
Rectangle r;
Rectangles rectangles;
r.set_values(4,3);
rectangles.addRectangle(&r);
cout<<"r.area() before change:"<<r.area()<<endl;
cout<<"rectangles.rects[0]->area() before change:"<<rectangles.rects[0]->area()<<endl;
r.set_values(4,4);
cout<<"r.area() after change:"<<r.area()<<endl;
cout<<"rectangles.rects[0]->area() after change:"<<rectangles.rects[0]->area()<<endl;
return 0;
}
输出:
r.area() before change:12
rectangles.rects[0]->area() before change:12
r.area() after change:16
rectangles.rects[0]->area() after change:16
答案 1 :(得分:1)
您的代码有什么问题是您对Rectangles
的定义。它将指针(或数组)存储到Rectangle
。你想要的不是Rectangle
的数组,而是引用的数组到Rectangle
的数组。这里, references 应该是指针,所以你需要相应地改变它:
class Rectangles {
public:
Rectangles(int n);
void addRectangle(Rectangle* r);
// Rectangle* rects;
// What you really want :
Rectangle** rects;
int nRects;
};
但是你还需要改变实现:
Rectangles::Rectangles(int n) {
rects = new Rectangle*[n]; // Array of pointers
nRects = 0;
}
void Rectangles::addRectangle(Rectangle* r) {
rects[nRects] = r; // r is a pointer : just store it, no dereferencing
nRects++;
}
然而,这是一个糟糕的设计:你不应该使用以下任何一个:指针指针(或指针的'原始数组),new
,以及一个唯一的目的是存储一个一系列的事情。这是因为你已经有了更好的工具:智能指针(尽管你也不需要它们),数组和动态数组(或向量)。
所以,如果我是你,这就是我重写代码的方式:
#include <iostream>
#include <vector>
class Rectangle {
public:
void setSize(int w, int h);
int area();
private:
int width, height;
};
void Rectangle::setSize(int w, int h) {
width = w;
height = h;
}
int Rectangle::area() {
return width * height;
}
int main() {
Rectangle r;
std::vector<Rectangle*> rectangles;
r.setSize(4, 3);
rectangles.push_back(&r);
std::cout << "r.area() before change : " << r.area() << std::endl
<< "rectangles[0]->area() before change : "
<< rectangles[0]->area() << std::endl;
r.setSize(4, 4);
std::cout << "r.area() after change : " << r.area() << std::endl
<< "rectangles.rects[0]->area() after change : "
<< rectangles[0]->area() << std::endl;
return 0;
}
修改:
您可能想知道为什么我使用原始指针而不是智能指针(因为我告诉您要避免指向指针)。这很简单:没有智能指针适合这件事。让我们看看为什么。
std::unique_ptr
保留对象的唯一所有权。如果您想要另一个参考,该怎么办?此外,如果您通过std::vector
的{{1}}销毁此智能指针,它也会破坏您的对象。因此,如果您之后访问它,您将收到一些脏错误。
erase
保持对象的共享所有权。当然,你可以对你的对象有另一个引用,但如果你破坏指针也会发生同样的事情。此外,它有一些开销,并不是很容易正确使用。
std::shared_ptr
与std::weak_ptr
一起使用,仅此而已。
相反,原始指针只需要确保对象的生命周期长于或等于其自身的生命周期,这样您就可以始终通过指针访问对象。这就是全部。
最后,here is a general rule of thumbs(我使用):
- unique_ptrs 仅供所有权使用
- 原始指针意味着谁给了我原始指针,保证该对象的生命周期匹配或超过我的生命。
- shared_ptrs 用于共享所有权
- weak_ptrs 适用于系统在使用之前检查对象是否仍然存在的情况。这在我的代码中很少见,因为我发现系统保证它通过子系统的任何生命周期都很清晰(在这种情况下我使用原始指针)