类和对象部分
浅拷贝与深拷贝的问题
(Code::Blocks编译)
#include <iostream>
#include <cstring>
using namespace std;
//定义Teacher类
class Teacher
{
public:
Teacher(int _id,const char *_name) // 这里加const则不会出现warning
{
cout << "调用构造函数" << endl;
id = _id;
//复制字符串的内容,最后有空字符‘/0’
int len = strlen(_name);
name = new char(len+1); //动态分配内存
strcpy(name,_name);
}
~Teacher()
{
if (name != NULL)
delete name; //释放占用的内存
name = NULL;
cout << "调用析构函数释放内存" << endl;
}
void printT()
{
cout << "id: " << id <<endl;
//cout << "name: " << *name << endl; //输出第一个字符的值
cout << "name: " << name << endl; //输出字符串的值
}
private:
int id;
char *name;
};
int main()
{
Teacher t1(25,"lvxiaoning");
t1.printT();
Teacher t2(t1);
t2.printT();
return 0;
}
以上程序
t1用来初始化t2后会调用默认的拷贝构造函数,使得对象t1和t2的成员变量指向堆中的同一块内存,同一块内存被析构两次后程序不应该coredump吗?为何可以正确编译运行?
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Teacher
{
public:
//有参数的构造函数
Teacher(int id, char *name)
{
cout << "调用了Teacher 的构造函数" << endl;
//是给id 赋值
m_id = id;
//给姓名赋值
int len = strlen(name);
m_name = (char*)malloc(len + 1);
strcpy(m_name, name);
}
//显示写一个拷贝构造函数
//通过显示拷贝构造函数提供了深拷贝的动作
//Teacher(const Teacher &another)
//{
// m_id = another.m_id; //给id赋值
// int len = strlen(another.m_name);
// m_name = (char*)malloc(len + 1);
// strcpy(m_name, another.m_name);
//}
~Teacher() {
//在构造函数中, 已经开辟了内存 所以为了防止泄露
//在析构函数中,在对象销毁之前,把m_name的内存释放掉
if (m_name != NULL) {
free(m_name);
m_name = NULL;
cout << "释放掉了m_name" << endl;
}
}
private:
int m_id;
char *m_name;
};
int main(void)
{
Teacher t1(1, "zhang3");
//如果不提供一个显示的拷贝构造函数, 通过系统自带的默认拷贝构造函数
Teacher t2(t1); //会调用t2的拷贝构造函数,将t1的值拷贝给t2
return 0;
}
附例(VS2010编译)
以上例子在VS2015中时不需要写以下的头文件也可以正常编译运行,而Code::Blocks中则需要包含。
#include <cstring> //
#include <stdlib.h> //包含malloc(),free()函数
以上例子在VS2015中运行确实会出现以下图片显示的中断。。原因确如上述吧。QAQ
结论:
例程序在VS2015中运行会出现由于调用默认拷贝函数(浅拷贝),同一块内存被析构两次后会触发中断异常;而在Code::Blocks中却能正常运行;说明不同的编译器对C++程序的响应不同,有时会得出截然不同的结果。
#include <cstring> //不可以定义string s;可以用到strcpy等函数
#include <string> //可以定义string s;但是不可以用到strcpy等函数,属于STL范畴
更新
在VS2015中对应上例第一个的正确程序,重写拷贝构造函数,new要分配的是字符数组,采用中括号,小括号是初始化。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
//定义Teacher类
class Teacher
{
public:
Teacher(int _id, const char *_name) // 这里加const则不会出现warning
{
cout << "调用构造函数" << endl;
id = _id;
//复制字符串的内容,最后有空字符‘/0’
int len = strlen(_name);
name = new char[len + 1]; //动态分配内存
strcpy(name, _name);
}
//使用默认的拷贝构造函数(浅拷贝)会触发断点
//要使用深拷贝,重写拷贝构造函数
Teacher(const Teacher &obj)
{
cout << "调用拷贝构造函数" << endl;
id = obj.id;
int len = strlen(obj.name);
name = new char[len + 1];
strcpy(name, obj.name);
}
~Teacher()
{
if (name != NULL)
{
delete [] name; //释放占用的内存
name = NULL;
cout << "调用析构函数释放内存" << endl;
}
}
void printT()
{
cout << "id: " << id << endl;
//cout << "name: " << *name << endl; //输出第一个字符的值
cout << "name: " << name << endl; //输出字符串的值
}
private:
int id;
char *name;
};
int main()
{
Teacher t1(25, "lvxiaoning");
t1.printT();
Teacher t2(t1);
t2.printT();
return 0;
}
对象初始化列表和匿名对象的接收问题
//构造函数对象初始化列表练习
#include <iostream>
using namespace std;
class ABCD
{
public:
ABCD(int _a, int _b, int _c)
{
a = _a;
b = _b;
c = _c;
cout << "构造函数运行;a,b,c的值分别为:" << a << " " << b << " " << c << endl;
}
~ABCD()
{
cout << "析构函数运行;a,b,c的值分别为:" << a << " " << b << " " << c << endl;
}
int getA()
{
return a;
}
private:
int a;
int b;
int c;
};
class Mye
{
public:
Mye() :abcd1(1, 2, 3), abcd2(4, 5, 6), m(100) //对象初始化列表,类中包含的类和常整数声明
{
cout << "Mye()" << endl;
}
Mye(const Mye &obj):abcd1(7,8,9),abcd2(10,11,12),m(100)
{
cout << "Mye(const Mye &obj)" << endl;
}
~Mye()
{
cout << "~Mye()" << endl;
}
//private:
public:
ABCD abcd1;
ABCD abcd2;
const int m;
};
int doThing(Mye mye1)
{
cout << "mye1.abcd1.a = " << mye1.abcd1.getA() << endl; //=7
return 0;
}
//对象初始化列表的应用;类里包含的声明类的对象的构造函数先执行
int run()
{
Mye mye;
doThing(mye); //调用拷贝构造函数
return 0;
}
//匿名对象的接收问题
int run2()
{
cout << "run2 start.." << endl;
ABCD(400, 500, 600); //产生的匿名对象会立即被析构
ABCD abcd = ABCD(700, 800, 900);
cout << "run2 end.." << endl;
return 0;
}
int main()
{
//run();
run2();
return 0;
}