首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在c++中保持类之间的多个引用?

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

Stack Overflow用户
提问于 2014-09-03 08:47:53
回答 1查看 479关注 0票数 0

我有两个类,在示例中添加了矩形和矩形。目标是使一个矩形对象保存对多个矩形对象的引用。

如果我把r改为r.set_values(4,4),那么粗r.area()就变了。但是,如果我调用rectangles.rects[0].area(),它仍然是12,因此不会更改。

据我所知,我在rectangles中引用了rectangles,但这似乎是错误的。

如何做到这一点?

代码是可用的这里

代码语言:javascript
运行
复制
#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;
}

输出:

代码语言:javascript
运行
复制
r.area() before change:12 
rectangles.rects[0].area() before change:12 
r.area() after change:16 
rectangles.rects[0].area() after change:12
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-09-03 09:16:53

代码的问题在于您对Rectangles的定义。它存储指向Rectangle的指针(或数组)。这里您想要的不是一个Rectangle的数组,而是一个对Rectangle的引用数组。在这里,引用应该是指针,因此您需要相应地更改它:

代码语言:javascript
运行
复制
class Rectangles {
    public:
    Rectangles(int n);
    void addRectangle(Rectangle* r);

    // Rectangle* rects;
    // What you really want :
    Rectangle** rects;

    int nRects;
};

但是,您还需要更改实现:

代码语言:javascript
运行
复制
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和一个类,其唯一目的是存储一个事物数组。这是因为您已经有了更好的工具:智能指针(尽管这里也不需要它们)、数组和动态数组(或向量)。

所以,如果我是你,我会这样重写你的代码:

代码语言:javascript
运行
复制
#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::vectorerase销毁这个智能指针,它也会破坏您的对象。因此,如果您事后访问它,您将得到一些肮脏的错误。

std::shared_ptr保持对象的共享所有权。当然,您可以有另一个对对象的引用,但如果销毁指针,也会发生同样的情况。另外,它也有一些开销,并且不太容易正确使用。

std::weak_ptrstd::shared_ptr一起工作,没什么可说的。

相反,原始指针只需要确保对象的生存期更长或等于它自己的生命周期,这样就可以始终通过指针访问对象。仅此而已。

最后,这是拇指的一般规则 (我使用的):

  • unique_ptrs为独资企业。
  • 原始指针是指给我提供原始指针的人保证该对象的生存期匹配或超过我的生命周期。
  • shared_ptrs用于共享所有权
  • weak_ptrs用于系统在使用对象之前要检查对象是否仍然存在。这在我的代码中是很少见的,因为我发现让一个系统保证它传递的任何子系统的生命周期都更干净--在这种情况下,我使用了一个原始指针。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25640017

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档