如何在c ++中保持类之间的多个引用?

时间:2014-09-03 08:47:54

标签: c++ oop object pass-by-reference

我有两个类,在示例中添加了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

2 个答案:

答案 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_ptrstd::weak_ptr一起使用,仅此而已。

相反,原始指针只需要确保对象的生命周期长于或等于其自身的生命周期,这样您就可以始终通过指针访问对象。这就是全部。

最后,here is a general rule of thumbs(我使用):

  
      
  • unique_ptrs 仅供所有权使用
  •   
  • 原始指针意味着谁给了我原始指针,保证该对象的生命周期匹配或超过我的生命。
  •   
  • shared_ptrs 用于共享所有权
  •   
  • weak_ptrs 适用于系统在使用之前检查对象是否仍然存在的情况。这在我的代码中很少见,因为我发现系统保证它通过子系统的任何生命周期都很清晰(在这种情况下我使用原始指针)
  •