gpt4 book ai didi

c++ - 如何克隆包含指针的对象?

转载 作者:太空狗 更新时间:2023-10-29 20:28:30 24 4
gpt4 key购买 nike

我有一个问题。我需要克隆包含指针的对象类。该问题的示例在以下代码中:

#include "stdafx.h"
#include <iostream>
#include <string.h>
#include <vector>

class CPoint
{
protected:
int m_x;
int m_y;

int *m_p;

public:
CPoint();
CPoint(int x, int y);
~CPoint();

CPoint* clone();
static CPoint* clone(CPoint& p);

int getX();
int getY();
void setX(int x);
void setY(int y);

void toString();
};

int CPoint::getX()
{
return m_x;
}

int CPoint::getY()
{
return m_y;
}

void CPoint::setX( int x )
{
m_x = x;
}

void CPoint::setY( int y )
{
m_y = y;
}

void CPoint::toString()
{
std::cout << "(" << m_x << ", " << m_y<< ", " << *m_p << ")" << std::endl;
}

CPoint::CPoint( int x, int y )
{
m_x = x;
m_y = y;

m_p = new int();
*m_p = x + y;
}

CPoint::CPoint()
{
m_p = new int();
*m_p = 1000;
}

CPoint* CPoint::clone()
{
CPoint *p = new CPoint();
*p = *this;
return p;
}

CPoint* CPoint::clone( CPoint& p )
{
CPoint *q = new CPoint();
*q = p;
return q;
}

CPoint::~CPoint()
{
if (m_p) {
delete m_p;
m_p = NULL;
}
}

int _tmain(int argc, _TCHAR* argv[])
{
CPoint *p1 = new CPoint(10, 20);
CPoint *p2 = new CPoint(30, 40);

p1->toString();
p2->toString();

CPoint *p3;
p3 = CPoint::clone(*p1);

p3->toString();

CPoint *p4;
p4 = p2->clone();

p4->toString();

p1->setX(50);
p1->setY(60);
p2->setX(80);
p2->setY(90);

p3->toString();
p4->toString();

delete p1;
delete p2;
delete p3;
delete p4;

int a;
std::cin >> a;

return 0;
}

变量 m_p 的问题。当在p3p4上克隆对象p1p2时,内存地址为p1p3 不同,但m_p 地址相同。显然,当移除p1时,p3移除失败。 p2p4 是一样的。

如何克隆 CPoint 类对象?

最佳答案

您似乎正在将一些其他类 Java 语言的规则应用到 C++。
这是一个根本性问题,从长远来看会导致各种问题。

你需要学习 C++ 的习语。

在 C++ 中,您想使用 C++ 字符串 (std::string) 而不是 C-String 接口(interface)。

#include <string.h>   // C-Interface

// What you really want
#include <string> // C++ Interface

如果您的类包含一个指针,那么您可能做错了什么。 RAW 指针应该包裹在智能指针(或容器)中以正确控制它们的生命周期。如果您将指针放入业务类,那么您就违反了关注点分离原则。

class CPoint
{
protected:
int m_x;
int m_y;

int *m_p; // What is it supposed to be?
// Who owns it?

因为你的类有一个指针,它打破了三个规则。
如果您想管理此类中的指针(而您不想(打破关注点分离)),那么您应该已经实现了三规则(C++11 中的五规则)(查找)。如果您想了解如何处理 RAW 指针,请看这里 https://stackoverflow.com/a/1846409/14065

不需要克隆方法。这就是复制构造函数的用途。您不是在编写需要克隆的类(否则它会有一个虚拟析构函数)。您的类不是多态的,也不会派生自。因此复制构造函数将完美地工作。

CPoint*         clone();
static CPoint* clone(CPoint& p);

// Copy constructor looks like this:
CPoint(CPoint const& rjs)

// Assignment operator looks like this:
CPoint& operator=(CPoint& rhs)

但如果将您的 RAW 指针正确包装在适当的类中,则不需要这些。编译器生成的这些方法的默认版本可以正常工作。

彻底破坏封装的好方法。

int getX();
int getY();
void setX(int x);
void setY(int y);

串起来!船尾。您真正需要的是一种序列化方法。

void toString();

// serializer look like this:

friend std::ostream& operator<<(std::ostream& stream, CPoint const& data)
{
// Convert CPoint (data) to the stream.
return stream;
}

在 C++ 中,除非需要,否则我们不会动态创建对象。
在这里你不需要。创建本地对象效果更好,因为即使存在异常,它们的生命周期也能得到保证。

// Rather than dynamically creating them
CPoint *p1 = new CPoint(10, 20);
CPoint *p2 = new CPoint(30, 40);

// Just declare two local variables:
CPoint p1 = CPoint(10, 20);
CPoint p2(30, 40); // Alternative to the above but means the same.

// Much better to use operator<<
// Also shows the functions are badly named. You are not converting to string.
// but rather printing them to a stream.
p1->toString();
p2->toString();

std::cout << p1;
myFileStream << p2; // allows you to easily specify the actual stream.

复制构造函数更适合复制对象

CPoint *p3;
p3 = CPoint::clone(*p1);

// If we were still using pointers.
CPoint* p3 = new CPoint(p1);

// But much nicer to not even use pointers
CPoint p3(p1);

如果您在函数中看到手动调用 delete,这通常是设计错误。

delete p1;
delete p2;
delete p3;
delete p4;

如果你有指针将它们包装在像类这样的智能指针(或容器)中,那么它们可以异常安全地使用。这是因为对于本地对象,析构函数肯定会被调用,因此您的对象在超出范围时将正确删除指针。目前这段代码不是异常安全的,如果异常传播通过它们就会泄漏。

小提示:main() 比较特殊。如果您不指定返回值,编译器会为您生成 return 0;。如果您的应用程序没有错误状态,最好使用此功能向其他开发人员表明您的代码将始终干净地退出。

return 0;

我会这样重写:

#include <iostream>
#include <string>
#include <vector>

class CPoint
{
protected:
int m_x;
int m_y;

std::vector<int> m_p;

public:
// If you don't explicitly initialize m_x and m_y them
// they will have indeterminate (random) values.
CPoint() : m_x(0), m_y(0) {m_p.push_back(1000);}
CPoint(int x, int y) : m_x(x), m_y(y) {m_p.push_back(x + y);}

int getX() { return m_x;}
int getY() { return m_y;}
void setX(int x) { m_x = x;}
void setY(int y) { m_y = y;}

friend std::ostream& operator<<(std::ostream& stream, CPoint const& d)
{
return stream << "(" << d.m_x << ", " << d.m_y<< ", " << d.m_p[0] << ")" << std::endl;
}
};




int main(int argc, char* argv[])
{
CPoint p1(10, 20);
CPoint p2(30, 40);

std::cout << p1 << p2;

CPoint p3(p1);

std::cout << p3;

CPoint p4(p2);
std::cout << p4;

p1.setX(50);
p1.setY(60);
p2.setX(80);
p2.setY(90);

std::cout << p1 << p2 << p3 << p4;
int a;
std::cin >> a;
}

关于c++ - 如何克隆包含指针的对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12933080/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com