一个空类,经过C++编译器编译后会产生一些默认的函数,那具体有哪些函数呢,根据资料显示有6个,分别为默认构造函数,拷贝构造函数,析构函数,赋值运算符取址运算符,取地运算符(const版本)。
使用时的调用如下:
#ifndef CTEST_HH_
#define CTEST_HH_
#include <iosfwd>
class CTest
{
public:
CTest(); //默认构造函数
~CTest(); //析构函数
CTest(const CTest& str); //拷贝构造函数
CTest* operator &(); //取地址运行符(非const)
const CTest* operator &() const; //取地址运行符(const)
CTest& operator =(const CTest& str); //赋值运行符
CTest(const char *s); //有参构造函数
friend std::ostream& operator << (std::ostream& os, const CTest& str);
char* str; //存储数据
private:
//char* str;//存储数据
int len; //字符串长度
};
#endif // CTEST_HH_
#include "CTest.h"
#include <cstring>
#include <iostream>
CTest::CTest() //默认构造函数
{
std::cout << "默认构造函数================" << this << std::endl;
len = 0;
str = new char[len + 1];
str[0] = '\0';
}
CTest::~CTest() //析构函数
{
std::cout << "析构函数=====================" << this << " str=" << str << std::endl;
delete[]str;
}
CTest::CTest(const CTest& st) //拷贝构造函数
{
std::cout << "拷贝构造函数=================" << this << " str=" << st.str << std::endl;
if (this == &st)//这里会调用取地址运算符const
return;
delete []str;
len = st.len;
str = new char[len + 1];
strncpy_s(str, (len + 1), st.str, len + 1);
}
CTest* CTest::operator &() //取地址运行符(非const)
{
std::cout << "取地址运算符(非const)=======" << this << std::endl;
return this;
}
const CTest* CTest::operator &() const //取地址运算符(const)
{
std::cout << "取地址运算符(const)===========" << this << std::endl;
return this;
}
CTest& CTest::operator =(const CTest& st) //赋值运算符
{
std::cout << "赋值运算符================str=" << st.str << std::endl;
if (this == &st)//这里会调用取地址运算符const
return *this;
delete[]str;
len = st.len;
str = new char[len + 1];
strcpy_s(str, (len + 1), st.str);
//strcpy(str, st.str);
return *this;
}
CTest::CTest(const char* s) //有参构造函数
{
std::cout << "重载构造函数=================" << this << " str=" << s << std::endl;
len = strlen(s);
str = new char[len + 1];
strcpy_s(str,(len + 1), s);
//strcpy(str, s);
}
std::ostream& operator << (std::ostream& os, const CTest& str)
{
os << str.str;
return os;
}
//main.cpp
#include "CTest.h"
#include <iostream>
int main()
{
CTest test1;//默认构造函数
std::cout << "1=======================================\n";
CTest test2("camle");//调用重载构造函数
std::cout << "2=======================================\n";
test1 = test2;//赋值运算符 (如果没有赋值运算符重载,test1和test2的str指向同一块内存,会释放两次)
std::cout << "test1====" << test1 << " test2===" << test2 << "\n";
std::cout << "3=======================================\n";
CTest* test3 = new CTest(test2);//调用拷贝构造函数 (如果没有重载拷贝构造函数,下面的delete test4析构时会把test2的内存释放掉,test2再析构时就会出错)
std::cout << "4=======================================\n";
CTest* test4 = &test2;//调用取地址运算符
std::cout << "5=======================================\n";
const CTest test5;//调用取地址运算符(const)
&test5;
std::cout << "7=======================================\n";
delete test3;//调用析构函数
std::cout << "hello world\n";
return 0;
}
大部分情况下,我们不需要重载这些函数,但如果类里有内存的申请变化,就需要重载部分函数,例如,如果不重载=赋值运算符,
test1 = test2;//赋值运算符
test1和test2的str指向同一块内存,析构时这块内存会释放两次
如果不重载拷贝构造函数,
则delete test3; 释放的是test2的空间,test2的空间会多次释放
注意:
1.有些书上只是简单的介绍了前四个函数。没有提及后面这两个函数。但后面这两个函数也是空类的默认函数。
另外需要注意的是,只有当实际使用这些函数的时候,编译器才会去定义它们。
2.自定义的拷贝构造函数不仅会覆盖默认的拷贝构造函数,也会覆盖默认的构造函数。
下面的代码是编译不过的,用户必须再显式的定义一个无参的构造函数。
class Empty {
public:
Empty(const Empty& e) //拷贝构造函数
{
}
};
int main(int argc, char** argv)
{
Empty a;
return 0;
}
编译时报错
严重性 代码 说明 项目 文件 行 禁止显示状态
错误 C2512 “Empty”: 没有合适的默认构造函数可用