1. 类的代码
#pragma warning(disable:4996)
#include<iostream>
#include<string>
using namespace std;
class StrBlobPtr
{
public:
//构造函数1不带参数,直接初始化(必须自己写,用new开辟空间,不能使用默认)
StrBlobPtr() : ptrChar(new char[1024]), n(0){} //在堆中动态创建存储空间
//构造函数2,带两个形参
StrBlobPtr(char*,size_t); //必须在堆中创建对象 (可以类内声明,类外定义)
//自定义拷贝构造函数
// StrBlobPtr(const StrBlobPtr&);
//重载赋值操作符
StrBlobPtr &operator=(const StrBlobPtr & rhs)
{
cout << "赋值操作符在运行" << endl;
char *ptrCharNew = new char[1024];
delete ptrChar;
ptrChar = ptrCharNew;
strcpy(ptrChar, rhs.ptrChar);
n = rhs.n;
return *this;
}
~StrBlobPtr(){ delete ptrChar; };
void Print()const;
//必须通过成员函数才能操作私有成员变量
int set_val(const int &) ;
char* set_str_val(char * );
private:
char *ptrChar;
size_t n;
};
StrBlobPtr::StrBlobPtr(char *cstr,size_t pa) //构造函数2
{
ptrChar=new char[1024];
strlen(ptrChar,cstr);
n=pa;
}
StrBlobPtr::StrBlobPtr(const StrBlobPtr&rhs)//自定义拷贝构造函数
{
ptrChar = new char[strlen(rhs.ptrChar) + 1];
strcpy(ptrChar, rhs.ptrChar);
n = rhs.n;
}
int StrBlobPtr::set_val(const int &x)
{
n = x;
return n;
}
char *StrBlobPtr::set_str_val(char* ptr)
{
*ptrChar = *ptr;
return ptrChar;
}
void StrBlobPtr::Print()const
{
cout << ptrChar<<"\t"<<n<< endl;
}
int main()
{
StrBlobPtr A("Bane",100); //调用构造函数2
StrBlobPtr B(A); //调用拷贝函数(默认的或者自定义的)
A.Print(); //打印出类的成员变量
B.Print();
B.set_val(10); //改变类对象B的成员变量 n
B.set_str_val("Tom"); //改变类对象B的成员变量 *ptrChar
A.Print(); //打印出改变过后类的对象A和B的成员
B.Print();
//测试赋值操作符
StrBlobPtr C;
C = A;
system("pause");
return 0;
}
2.类的分析
2.1构造函数(参数不限定,可以多个)
一般编译器都会自己添加默认的构造函数,起到初始化成员变量的作用。但是不是所有的类都依赖于编译器自己合成的默认构造函数。有时需要自己添加构造函数。
- 默认构造函数:不开辟堆空间,仅仅是分配一个栈内存,它可以由编译器自动创建和销毁。
- 自定义构造函数:完全可以替代默认构造函数,并且可以开辟动态内存,申请堆空间,后期必须显示地调用析构函数销毁。
- 本例中,因为成员变量含有指针,必须自定义构造函数,来申请动态内存!
2.2拷贝构造函数(StrBlobPtr(const StrBlobPtr&))
一般也是有编译器添加默认拷贝函数,但是一旦使用自定义构造函数声请了动态内存,也必须自定义拷贝构造函数,才能达到深度拷贝(拷贝内容)的作用。否则只是浅拷贝(拷贝的是指针)。
程序运行效果
上面程序中,调用自定义构造函数2开辟了堆空间,初始化类对象A,再把A拷贝给B,如果调用的是默认构造函数,改变B中内容后,影响到A;如果调用的是自定义拷贝函数,改变B的内容后,A不变。
2.3 赋值操作符(关于重载的问题后期将继续探讨)
3.个人总结
- 深复制,浅复制的概念只能在开辟了堆空间的情况下才存在,因为在栈中的赋值都是直接复制值(广义上的深度复制)。
- 关于char *的探讨后期继续。