目录
1.对象的初始化和清理
class Person
{
public:
//构造函数写法
//与类名相同,没有返回值,不写void,可以发生重载(可以有参数)
//构造函数由编译器自动调用,而不是手动调用,而且只会调用一次
Person()
{
cout << "默认无参构造函数" << endl;
}
Person(int a)
{
cout << "有参构造函数" << endl;
}
//析构函数写法
//与类名相同,类名前面加一个符号,“~”,也没有返回值,不写void,不可以有参数(不能发生重载)
//析构函数由编译器自动调用,而不是手动调用,而且只会调用一次
~Person()
{
cout << "析构函数" << endl;
}
};
//如果程序员没有提供构造和析构,系统会默认提供,空实现
Person p1(2);//默认调用了构造和析构,是系统提供的两个空实现的函数
2.构造函数的分类及调用
按照参数进行分类:无参构造函数(默认构造函数) 有参构造函数
按照类型进行分类:普通构造函数 拷贝构造函数
class Person
{
public://构造函数和析构函数必须写在public下才可以调用
Person() //默认、无参构造函数
{
cout << "默认构造函数的调用" << endl;
}
Person(int a)
{
cout << "有参构造函数的调用" << endl;
}
//拷贝构造函数
Person(const Person& p)
{
mage = p.mage;
cout << "拷贝构造函数的调用" << endl;
}
~Person()
{
cout << "默认析构函数的调用" << endl;
}
int mage = 0;
};
void test()
{
//构造函数调用方式
//1.括号法调用
//Person p1(1);//有参
//p1.mage = 10;
//Person p2(p1);//拷贝
//cout << "p2的年龄:" << p2.mage << endl;
//Person p3;//默认构造函数不要加()Person p3();编译器认为这是函数声明
//2.显示法调用
//Person p4 = Person(100);
//Person p5 = Person(p4);
//Person(100); //匿名对象,匿名对象的特点:如果编译器发现对象是匿名的,那么在这行代码结束后就释放
//不能用拷贝构造函数初始化匿名对象
//Person p6 = Person(p5);//如果写成左值,编译器认为你写成了Person p5,对象的声明;如果写成右值可以
Person p7 = 100;//相当于调用了 Person p7 = Person(100),隐式类型转换
Person p8 = p7; //相当于Person p8 = Person(p7)
}
3.拷贝构造函数的调用时机
class Person
{
public:
Person()
{
cout << "默认构造函数的调用" << endl;
}
Person(int a)
{
cout << "有参构造函数的调用" << endl;
}
Person(const Person& p)
{
cout << "拷贝构造函数的调用" << endl;
}
~Person()
{
cout << "析构函数的调用" << endl;
}
int age = 0;
};
拷贝调用的时机
1.用已经创建好的对象来初始化新的对象
void test1()
{
Person p1;
p1.age = 18;
Person p2(p1);
}
2.以值传递的方式给函数参数传值
void dowork(Person p1)//Person p1 = Person(p)
{
}
void test2()
{
Person p;
p.age = 18;
dowork(p);
}
3.以值的方式返回局部对象
Person dowork2()
{
Person p1;
return p1;
}
void test3()
{
Person p = dowork2();
}
//Release默认下会做优化
4.构造函数的调用规则
class Myclass
{
public:
/*Myclass()
{
cout << "默认构造函数的调用" << endl;
}*/
Myclass(int a)
{
cout << "有参构造函数的调用" << endl;
}
/*Myclass(const Myclass& c)
{
cout << "拷贝构造函数的调用" << endl;
}*/
~Myclass()
{
cout << "默认析构函数的调用" << endl;
}
int m_a = 0;
};
//系统默认给一个类提供3个函数:默认构造函数、拷贝构造函数、析构函数
//1.当我们提供有参的构造函数,那么系统就不会再给我们提供默认构造函数了
//但是系统还会提供默认的拷贝构造函数,进行简单的值拷贝
//2.当我们提供了拷贝构造函数,系统就不会提供其他构造函数了
void test1()
{
Myclass c1(1);
c1.m_a = 10;
Myclass c2(c1);
cout << c2.m_a << endl;
}
5.深拷贝和浅拷贝
class Person
{
public:
Person()
{}
//构造函数用来初始化属性
Person(const char* name, int age)
{
m_Name = (char*)malloc(strlen(name) + 1);
if (m_Name != NULL)
{
strcpy(m_Name, name);
}
m_age = age;
}
//拷贝构造,系统会提供默认拷贝构造函数,而且是简单的值拷贝(浅拷贝)
//自己提供拷贝构造,原因是简单的浅拷贝会释放空间两次,导致崩溃
//深拷贝
Person(const Person& p)
{
m_age = p.m_age;
m_Name = (char*)malloc(strlen(p.m_Name) + 1);
if (m_Name != NULL)
{
strcpy(m_Name, p.m_Name);
}
}
~Person()
{
cout << "析构函数调用" << endl;
if (m_Name != NULL)
{
free(m_Name);
m_Name = NULL;
}
}
//姓名
char* m_Name;
//年龄
int m_age = 0;
};
6.初始化列表的基本使用
class Person
{
public:
/*Person()
{
}*/
//有参构造初始化数据
/*Person(int a,int b,int c)
{
ma = a;
mb = b;
mc = c;
}*/
//利用初始化列表来初始化数据
//构造函数后面 + :属性(参数),属性(参数)...
1. Person() :ma(10), mb(20), mc(30)
{}
2. Person(int a, int b, int c) :ma(a), mb(b), mc(c)
{}
int ma;
int mb;
int mc;
};
7.类对象作为成员的案列
class Person
{
public:
Person()
{
cout << "Person的默认构造函数" << endl;
}
Person(string name,string phonename,string gamename):mname(name),m_Phone(phonename),m_Game(gamename)
{
cout << "Person的有参构造函数" << endl;
//mname = name;
}
void playGame()
{
cout << mname << "拿着《" << m_Phone.m_Phonename << "》牌手机,玩着《" << m_Game.m_Gamename << "》游戏" << endl;
}
~Person()
{
cout << "Person的析构函数" << endl;
}
Phone m_Phone;
string mname;
Game m_Game;
};
class Phone
{
public:
Phone()
{
cout << "手机的默认构造函数" << endl;
}
Phone(string name)
{
m_Phonename = name;
cout << "手机的有参构造函数" << endl;
}
~Phone()
{
cout << "手机的析构函数" << endl;
}
string m_Phonename;
};
class Game
{
public:
Game()
{
cout << "游戏的默认构造函数" << endl;
}
Game(string name)
{
m_Gamename = name;
cout << "游戏的有参构造函数" << endl;
}
~Game()
{
cout << "游戏的析构函数" << endl;
}
string m_Gamename;
};
//类对象作为类成员时,构造的顺序先将类对象一一构造,再构造自己,析构与之相反
8.explicit关键字
//作用:防止构造函数中的隐式类型转换
class MyString
{
public:
MyString(const char* str)
{}
explicit MyString(int a)
{
mSize = a;
}
char* mstr;
int mSize;
};
void test()
{
MyString str = "abc";
MyString str2(10);
//MyString str3 = 10;//str2字符串为"10",字符串长度为10
//隐式类型转换 MyString str3 = MyString(10)
//explicit关键字,防止隐式类型转换
}
9.new运算符使用
class Person
{
public:
Person()
{
cout << "默认构造调用" << endl;
}
Person(int a)
{
cout << "有参构造调用" << endl;
}
~Person()
{
cout << "析构函数调用" << endl;
}
};
void test()
{
//Person p1;放在栈区开辟
Person* p2 = new Person;//在堆区开辟
//所有new出来的对象,都会返回该类型的指针
//malloc返回void* 还要强转
//malloc不会调用构造函数
//new运算符 malloc函数
//释放堆区空间
//delete也是运算符,配合new用;malloc配合free用
delete p2;
}
void test2()
{
void *p = new Person;
//当用void*接受new出来的指针,会出现释放的问题
delete p;
//无法释放,避免这种写法
}
void test3()
{
//通过new来开辟数组,一定会调用默认构造函数,所以一定要提供默认构造函数
Person* pArray = new Person[10];
//Person pArray[2] = {Person(1),Person(2)};//在栈上开辟数组,可以指定有参构造
//释放数组
delete [] pArray;
}