- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个问题。我需要克隆包含指针的对象类。该问题的示例在以下代码中:
#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
的问题。当在p3
和p4
上克隆对象p1
和p2
时,内存地址为p1
和p3
不同,但m_p
地址相同。显然,当移除p1
时,p3
移除失败。 p2
和p4
是一样的。
如何克隆 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/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!