測試代碼如下
#include <iostream>
#include <string>
using namespace std;
class StupidClass{
int flag;
string name;
int* data;
public:
StupidClass(int flag, string name) : flag(flag), name(name){
cout << "Constructor " << flag << " " << name << endl;
data = new int;
*data = flag * 3;
}
~StupidClass(){
cout << "Destructor " << flag << " " << name << " " << data << endl;
if (data != nullptr)
{
delete data;
}
}
/*
StupidClass(const StupidClass& rhs){
this->flag = rhs.flag;
this->name = rhs.name;
data = new int;
*data = flag * 3;
cout << "Copy Constructor *this=" << flag << " rhs.flag=" << rhs.flag << endl;
cout << "Copy Constructor *this=" << name << " rhs.name=" << rhs.name << endl;
}
*/
StupidClass& operator=(const StupidClass& rhs){
this->flag = rhs.flag;
this->name = rhs.name;
data = new int;
*data = flag * 3;
cout << "Operator = *this=" << flag << " rhs.flag=" << rhs.flag << endl;
cout << "Operator = *this=" << name << " rhs.name=" << rhs.name << endl;
return *this;
}
};
int main()
{
StupidClass var1(1, "var1"), var2(2, "var2");
//StupidClass var3 = var1;
return 0;
}
問題是這樣的,在執行StupidClass var3 = var1;這一句時,我以爲是調用重載=運算符,但是實際情況是調用了複製拷貝函數,很奇怪。
當我把複製拷貝函數註釋掉的,單步調試,執行上述語句的時候,並沒有進入到重載=運算函數的內部,直接跳到下一步,也沒用進到其他函數內部,然後接着程序崩潰了。
崩潰的地方是在調用第三次析構的時候出錯了。
發現第三次析構的地址和第一次是一樣的,應該是多次析構同一個指針
那爲什麼var1和var3的data指針的地址一樣呢?
首先StupidClass var3 = var1;在這裏是要調用拷貝構造函數的,不會調用重載的=運算符,如果是:
StupidClass var3;
var3 = var1;
這裏就會調用重載=運算符。
StupidClass var3 = var1;這裏應該是調用了淺層拷貝構造函數,僅僅是簡單的一對一的複製拷貝,所以var1和var3的data所指向的地址是一樣的。
所以當類的成員比較複雜的時候,最好還是要有一個深層構造函數。
/*******************string.h*************************/
#ifndef STRING_H
#define STRING_H
#include <iostream>
class String {
friend std::ostream& operator<<(std::ostream& os, const String& str);
public:
String(const char* cstr = 0);
String(const String& str);
~String();
String& operator=(const String& str);
char* get_c_str() const { return m_data; }
private:
char* m_data;
};
#endif
/*******************string.cpp**********************/
#include "string.h"
#include <cstring>
String::String(const char * cstr)
{
if (cstr) {
m_data = new char[strlen(cstr) + 1];
strcpy(m_data, cstr);
}
else {
m_data = new char[1];
*m_data = '\0';
}
}
String::String(const String & str)
{
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data, str.m_data);
}
String::~String()
{
delete[] m_data;
}
String & String::operator=(const String & str)
{
// 自我賦值
if (this == &str)
return *this;
delete[] m_data;
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data, str.m_data);
return *this;
}
std::ostream& operator<<(std::ostream& os, const String& str)
{
os << str.get_c_str();
return os;
}
/*******************string.cpp**********************/
#include <iostream>
#include "string.h"
int main()
{
String s1("Hello World"), s2("I love you");
String s3 = s1; //調用深層拷貝函數
String s4;
s4 = s1; //調用賦值拷貝函數
std::cout << s3 << std::endl;
return 0;
}
注:本人正在學習狀態,文中多有引用,也有解釋紕漏之處,敬請包涵、指正!