【问题标题】:Interactions between pointers and classes [closed]指针和类之间的交互 ​​[关闭]
【发布时间】:2015-01-19 17:39:00
【问题描述】:

我最近一直在努力学习来自 java 和其他高级语言背景的 c++。我在指针和对象方面遇到了一些问题,但我还没有找到一个很好的资源来准确解释如何使用指针操作使用自定义类创建的对象。

我编写了一个简单的程序来尝试缩小我的问题所在。

这个类底部的最后两个代码块是错误的,我敢打赌我在其他部分也做错了一些事情。任何帮助表示赞赏。

#include <iostream>
#include <cstdlib>
#include <string.h>

using namespace std;

class Point {
public: 
    float x;
    float y;    
public: 
    Point(float x, float y) {
        this->x=x;
        this->y=y;
    }
    Point() {
        x=0.0f;
        y=0.0f;
    }
    ~Point() {
        x=0.0f;
        y=0.0f;
    }
};

class Place {
public: 
    string name;
    Point location;
public: 
    //Constructor with arguements.
    Place(string nam, Point loc) {
        name = nam;
        location = loc;
    }
    //Default constructor.
    Place() {
        name = "Default";
        location = {0.0f,0.0f};
    }
    //Destructor. This object contains no pointers so nothing to delete.
    ~Place() {

    }
public: 
    void setName(string nam) {
        name = nam;
    }
    void setLocation(Point loc) {
        location = loc;
    }
};

class PointerToAPlace {
public: 
    Place *place;
public:
    PointerToAPlace(Place *pl) {
        *place = *pl;
    }
    ~PointerToAPlace() {
        delete place;
    }
};

int main(int argc, char** argv) {
    std::cout << "\n";
    std::cout << "Make some places and hope they don't segfault.\n";


    /*Object created with default constructor. Will be automatically deleted at the end of this scope.*/
    Place placeA;
    std::cout << "Place named " << placeA.name.c_str() << " is at " << placeA.location.x << "," << placeA.location.y << " and is lovely.\n";
    //Output: Place named Default is at 0,0 and is lovely.


    /*Object created with bracket constructor. Will be automatically deleted at the end of this scope.*/
    Place placeB = {"Lordran", Point{12.2f,99.3f}};
    std::cout << "Place named " << placeB.name.c_str() << " is at " << placeB.location.x << "," << placeB.location.y << " and is lovely.\n";
    //Output: Place named Lordran is at 12.2,99.3 and is lovely.


    /*Object created with new keyword. This is a pointer and must be explicitly deleted.*/
    Place *placeC = new Place("Drangleic", Point{-123.34f,69.69f});
    std::cout << "Place named " << placeC->name.c_str() << " is at " << placeC->location.x << "," << placeC->location.y << " and is lovely.\n";
    delete placeC;
    //Output: Place named Drangleic is at -123.34,69.69 and is lovely.


    /*Array of objects, created with default constructor and not assigned any values. Will be automatically deleted at the end of this scope.*/
    Place placeD[3];
    std::cout << "Here are some places named: ";
    for(int i=0;i<3;i++) {
        std::cout << placeD[i].name.c_str();
        std::cout << (i<2 ? ", " : ". ");
    }
    std::cout << "They are quite the places!\n";
    //Output: Here are some places named: Default, Default, Default. They are quite the places!    


    /*Array of objects, created with default constructor and then assigned values. Will be automatically deleted at the end of this scope.*/
    Place placeE[5];
    string namesA[5] = {"Boletaria", "Stonefang", "Latria", "Shrine of Storms", "Valley of Defilement"};
    for(int i=0;i<5;i++) {
        placeE[i].setName(namesA[i]);
        placeE[i].setLocation(Point{1.23f, 3.21f});
    }
    std::cout << "Here are some places named: ";
    for(int i=0;i<5;i++) {
        std::cout << placeE[i].name.c_str();
        std::cout << (i<4 ? ", " : ". ");
    }
    std::cout << "They are quite the places!\n";
    //Output: Here are some places named: Boletaria, Stonefang, Latria, Shrine of Storms, Valley of Defilement. They are quite the places!


    /*Trying to do a pointer to an array of objects.*/
    Place *placeF[7];
    string namesB[7] = {"Astora", "Carim", "Thoroughland", "Catarina", "Baulder", "Vinheim", "Zena"};
    for(int i=0;i<7;i++) {
        placeF[i]->setName(namesB[i]);
        placeF[i]->setLocation(Point{2.23f, 6.21f});
    }
    std::cout << "Here are some places named: ";
    for(int i=0;i<7;i++) {
        std::cout << placeF[i]->name.c_str();
        std::cout << (i<6 ? ", " : ". ");
    }
    std::cout << "They are quite the places!\n";
    //Output: SEGFAULT D:

    /*Trying to put a pointer to a place into an object, then delete it.*/
    Place *placeG = new Place("Anor Londo", Point{-12312.34f,33.69f});
    PointerToAPlace pnt = {placeG};
    std::cout << "Place named " << pnt.place->name.c_str() << " is at " << pnt.place->location.x << "," << pnt.place->location.y << " and is lovely.\n";
    //Output: SEGFAULT :(

    return 0;
}

【问题讨论】:

  • 请提出具体问题。
  • 你的问题是什么?
  • 首先,这甚至不应该编译。 namesB 在初始化程序中有太多字符串。无论如何,您使用的是未初始化的指针,就好像它们指向一个有效对象一样。我也会考虑向codereview.stackexchange.com 发帖,了解如何更好地使用该语言(例如,Point 的无用析构函数)。
  • 感谢学习在 C++ 中创建对象的所有方法以及如何管理它们,而不是像我们经常看到的 Java 初学者那样到处使用 new

标签: c++ class pointers object c++11


【解决方案1】:
PointerToAPlace(Place *pl) {
    *place = *pl;
}

这是错误的,如果你想要做的是存储指针然后这样做:

PointerToAPlace(Place* pl) {
    place = pl;
}

或者更好的是,使用构造函数初始化列表:

PointerToAPlace(Place* pl) : place(p1) {
}

您当前的代码没有设置place,因此它包含一个垃圾值,指向谁知道在哪里,然后取消引用它(这是未定义的行为)。

你还需要小心复制PointerToAPlace,目前如果你复制它,你会得到两个对象都持有相同的指针,并且都会尝试删除它。

恕我直言,一旦您了解了语法的工作原理以及如何使用new/delete,您应该停止使用它们并改用智能指针。

【讨论】:

  • 谢谢。这更有意义,现在一切都在编译/运行。我还将研究 C++ 中指针的复制是如何工作的。在其他语言中,我总是为类定义一个特定的 copy() 方法,以确保不与原始类共享任何指针。我认为我应该在 C++ 中做同样的事情。
  • 这就是复制构造函数的用途。
【解决方案2】:
class PointerToAPlace {
public: 
    Place *place;
public:
    PointerToAPlace(Place *pl) {
        *place = *pl;
    }
    ~PointerToAPlace() {
        delete place;
    }
};

首先这是错误的。在将place 指向任何地方之前,您必须先尊重它。

大概你的意思是place = pl* 是类型的一部分,而不是名称。

如果你将指针声明写成Place* pl,而不是Place *pl,这对你来说会更清楚;不要听从 1970 年代的反对者,他们沉迷于多变量声明的边缘情况,因为这些是这种表示法的唯一缺点。

【讨论】:

  • 多变量声明如:int i, j, k;或int i=0,j=0,k=0;对吗?
【解决方案3】:
/*Trying to do a pointer to an array of objects.*/
Place *placeF[7];

不,这是一个由七个(未初始化)指针组成的数组,指向Place。因此,当您取消引用它们时,您会得到段错误。

【讨论】:

  • 谢谢,我不知道。现在开始工作了。 :)
【解决方案4】:

您应该为您的类添加一个复制构造函数。 如果没有,当一个类实例被压入堆栈时,你会遇到麻烦。 复制构造函数是将相同的类实例作为参数的构造函数:

Point(Point & original)
{
  // initialize this with original
}

编辑:在代码 sn-p 中添加缺少的“&”。

【讨论】:

  • 一般来说好点,但这不是一个有效的复制构造函数,它需要通过引用来获取它的参数。否则调用它将尝试复制对象以初始化参数,它调用复制构造函数,它尝试复制参数,它调用复制构造函数,它...
  • Point 不需要复制构造函数。
猜你喜欢
  • 2015-12-24
  • 1970-01-01
  • 1970-01-01
  • 2011-02-01
  • 2021-01-29
  • 1970-01-01
  • 2018-05-24
  • 1970-01-01
相关资源
最近更新 更多