new 运算符的作用:为的是在执行程序过程中,动态分配内存,从而减少 不必要的内存分配。
程序中有new,析构函数必不可少,new 对应delete 。
1、默认构造函数
eg:
class test{
public:
test();//a,第一种表示
test(int a=0,int b=10);//b,第二种表示
//所有参数都带默认值亦可以成为默认的构造函数
};
2、复制构造函数
- 概念:将一个对象复制到 新创建的对象中
- 作用:只会逐个复制非静态的值(静态成员属于整个类,不是每个对象),这个过程也被称为浅复制。
- 何时调用:当按值传递和返回对象时, 都将调用 复制构造函数
eg://将对象oldD复制给newD
test newD(oldD);
test newD=oldD;
test newD=test(oldD)
test *newD=new test(oldD);
以上均会复制构造函数
默认的复制构造函数逐个复制非静态成员的值(是值,非地址);
故应该按引用 传递对象,节约调用构造函数的时间以及存储新对象的空间。
结合代码
.h申明
class str
{
private:
char *strr;//字符指针
int len;//字符长度
static int num_strings;
public:
str();
str(const char*s);
~str();
friend std::ostream& operator<<(std::ostream &os, const str &st);
};
.cpp 实现
str::str() //1号构造函数
{
len = 4;
strr = new char[len];
strcpy_s(strr,4,"c++");
num_strings++;
std::cout << "default obj created" << "\n";
}
str::str(const char *s)//重载构造函数
{
len = std::strlen(s);
strr = new char[len + 1];
strcpy_s(strr,len+1,s);
num_strings++;
std::cout << "obj created" << "\n";
}
str::~str()
{ std::cout << "对象被删除" << "///" << strr<<"\n";
num_strings--;
std::cout <<"现存对象" << "///" <<num_strings<<"\n";
delete[] strr;//使用new [] 创建,必须使用delete[] 来释放;如果为new ,就对应delete即可
std::ostream &operator<<(std::ostream &os, const str &st)//重载运算符
{ os << st.strr << "\n";
return os;}
//str 的调用
//main函数调用
str a("bobobodadada");
str b;
str c = str("asssssssssd");
解释: 这么调用,在释放时不会出现问题,都有对应的构造函数,在释放的时候就能正确的释放。
再添加代码
callme1(a);
callme2(b);
void callme1(str & a)
{
cout << "引用\n"<<a;
}
void callme2(str a) //== str a=b;
{
cout << "值\n" << a;
}
解释:
a 引用传递,释放正常,因为不会创建临时变量。
b 按值传递,会报出两个错误如下: num_strings计数错误
报出字符串乱码,以及其他debug中止
b1:会复制构造函数,但是缺少 构造函数 str(const str &s),编译器只会浅复制,并不会执行num_strings++;故创建正常,释放时,数值出错。
b2:因为默认调用的是引用,所以两个变量指向的是同一个地址,由于调用callme2的完成后,将释放a;所以后面在释放callme2(b)的b的时候,就会出现访问地址错误(访问已经被释放的空间)
解决方案如下:
//一些类的成员 是通过动态分配的内存(为指针);这个时候就需要复制它的创建过程;这个过程被称为深复制。
str::str(const str &s)
{ len = s.len;
strr = new char[len + 1];
strcpy_s(strr, len + 1, s.strr);
num_strings++; //都会赋给对象的strr指针。所以不存在释放同一个地址的情况
}
继续添加代码
str dd;
dd=c;//程序到这都没有错
cout <<"dd="<<dd <<"\n";
cout << "c=" << c << "\n";
解释:运行程序报错。
因为调用赋值的时候没得默认的运算构造,系统默认调用 复制运算函数。就会导致两个函数一样,调用引用,和上面一样;对应c++primer plus 436页。
解决方案:对运算符深度复制;添加运算构造函数
str & str::operator=(const str & st)
{ if (this == &st)
return *this;
delete[] strr;
len = st.len;
strr = new char[len + 1];
strcpy_s(strr, len + 1, st.strr);
return *this;
}
//自检查 如果相等 返回this指针的地址;不相等释放空间,重新赋值。
小知识点
深度赋值:类成员如果有指针需要进行深度复制;
浅复制:只是复制变量值,浅复制即可。
c++ 的空指针为 nullptr。不要写成0;