5.12
1、构造函数与析构函数
#include<iostream>
using namespace std;
//构造函数和析构函数默认必须有
class Person
{
public:
//构造函数
//1、无返回值无void
//2、函数名与类名相同
//3、可以有参数,可以发生重载
//4、函数调用类对象之前先调用构造函数只调一次
Person()
{
cout << "构造函数" << endl;
}
//析构函数
//1、无无
//2、函数名与类名相同,前加~
//3、无参数,不重载
//4、函数释放类对象前先析构
~Person()
{
cout << "析构函数" << endl;
}
};
void test1()
{
Person p;
}
int main()
{
test1();//局部变量p函数执行完立即析构
Person p;//全局变量,执行完并不立即析构
system("pause");
return 0;
}
成员私有化设置中的构造与析构函数调用
#include<iostream>
using namespace std;
class Person
{
public:
Person()
{
cout << "构造" << endl;
}
~Person()
{
cout << "析构" << endl;
}
void setx(int x)
{
m_x = x;
}
int getx()
{
return m_x;
}
private:
int m_x;
};
void test1()
{
Person p1;
p1.setx(20);
cout<<p1.getx()<<endl;
}
int main()
{
Person p;
p.setx(10);
cout << p.getx() << endl;
test1();
system("pause");
return 0;
}
构造函数的分类与调用
#include<iostream>
using namespace std;
class Person
{
public:
//无参构造
Person()
{
cout << "无参构造" << endl;
}
//有参构造
Person(int a)
{
cout << "有参构造" << endl;
m_age = a;
}
//拷贝构造
Person(const Person& p)
{
cout << "拷贝构造" << endl;
m_age = p.m_age;
}
~Person()
{
cout << "析构" << endl;
}
int m_age;
};
//调用
void test1()
{
//括号法
Person p1;
Person p2(10);
Person p3(p2);
cout << p2.m_age << endl;
cout << p3.m_age << endl;
//注意事项
//无参构造括号法不加括号
//Person p1(); 编译器将之认作函数声明处理
}
void test2()
{
//显示法
//Person p1;
//Person p2 = Person(10);
//Person p3 = Person(p2);
//cout << p2.m_age << endl;
//cout << p3.m_age << endl;
//显示法中的匿名操作应用
//Person(10);匿名有参构造创建对象创建完毕后立即释放
//Person(p3);匿名拷贝构造函数创建对象,编译器将括号自动忽略,Person p3;重定义操作
}
void test3()
{
//隐式转换法
Person p1;
Person p2 = 10;
Person p3 = p2;
cout << p2.m_age << endl;
cout << p3.m_age << endl;
}
int main()
{
test2();
system("pause");
return 0;
}
拷贝构造函数的调用时机
//拷贝构造函数的调用时机
#include<iostream>
using namespace std;
class Person
{
public:
Person()
{
cout << "无参构造" << endl;
}
Person(const Person& p)
{
cout << "拷贝构造" << endl;
m_age = p.m_age;
}
int m_age;
};
//调用时机
void test1(Person& p)
{
Person p1 = p;
}
Person test2()
{
Person p1;
cout << (int)&p1 << endl;
return p1;//拷贝构造
//拷贝构造将函数的值返回时,先拷贝一份返回,原函数值直接释放
}
int main()
{
//1、复制对象
//Person p1;//无参构造
//Person p2(p1);//拷贝构造
//2、值传递
//test1(p1);//拷贝构造值传递将p1复制一份传入函数
//3、返回
Person p3 = test2();//无参构造
cout << (int)&p3 << endl;
system("pause");
return 0;
}
//构造函数的调用规则
//创建一个类,编译器默认三个构造函数,无参构造、有参构造、拷贝构造
//人为创建一个有参构造,则编译器仅保留拷贝构造
//人为创建一个拷贝构造,则编译器默认构造函数均不保留
2、深浅拷贝
浅拷贝的问题所在,简单的拷贝黏贴,如果在堆区开辟一块内存,则浅拷贝后两个指针指向同一个区域,释放的时候会出现某一个重复释放的非法操作,释放按照栈区先进后出的原则
解决方法,利用深拷贝,创建两个堆区内存
#include<iostream>
using namespace std;
class Person
{
public:
Person()
{
cout << "无参构造" << endl;
}
Person(int age,int height)
{
m_height=new int(height);
cout << "有参构造" << endl;
m_age = age;
}
Person(const Person& p)
{
cout << "拷贝构造" << endl;
m_age = p.m_age;
//m_height = p.m_height;默认浅拷贝操作,将p的指针拷贝一份,两个指针指向相同的堆区内存
//深刻拷贝操作,堆区开辟内存,存放p的指针解引用的数据
m_height = new int(*p.m_height);
}
~Person()
{
if (m_height != NULL)
{
delete m_height;
m_height = NULL;
}
cout << "析构" << endl;
}
int m_age;
int* m_height;
};
void test1()
{
Person p1(10,180);
cout << "p1年龄:"<< p1.m_age << "身高:" << *p1.m_height << endl;
Person p2(p1);
cout << "p2年龄:"<< p2.m_age << "身高:" << *p2.m_height << endl;
}
int main()
{
test1();
system("pause");
return 0;
}
3、类对象作为类成员
//类对象作为类成员
#include <iostream>
using namespace std;
class Phone
{
public:
Phone()
{
cout << "Phone默认构造" << endl;
}
//Phone(string pname)
//{
// m_pname = pname;
// cout << "Phone有参构造" << endl;
//}
~Phone()
{
cout << "Phone析构函数" << endl;
}
string m_pname;
};
class Person
{
public:
//Person(string name,string pname): m_name(name),m_p(pname)//初始化列表问题,基本格式
//{
// cout << "Person构造函数" << endl;
//}
//类对象作为类成员时,当不使用初始化列表的格式,要对Phone有个默认构造函数,
Person(string name, string pname)
{
cout << "Person构造函数" << endl;
m_name = name;
m_p.m_pname = pname;
}
~Person()
{
cout << "Person析构函数" << endl;
}
string m_name;
Phone m_p;
};
void test1()
{
Person person("张三", "apple");
cout << person.m_name << "拿着" << person.m_p.m_pname << "手机" << endl;
}
但其它类对象作为本类成员时,先构造其他类对象再构造本类对象
析构的顺序与构造相反
int main()
{
test1();
system("pause");
return 0;
}
4、静态成员变量
#include<iostream>
using namespace std;
class Person
{
//静态成员
//1、所有对象共享
//2、类内声明类外初始化
//3、有权限
//4、两种访问方式,类名访问和类对象访问
public:
static int m_age;
private:
static int m_height;
};
int Person::m_age = 10;
int Person::m_height = 180;
void test1()
{
Person p1;
cout << "p1年龄:" << p1.m_age << endl;
Person p2;
p2.m_age = 20;//在一个对象内将静态变量更改
cout << "p1年龄:" << p1.m_age << endl;//另一个对象里跟着更改,对象共享
}
void test2()
{
Person p1;
cout << "p1年龄:" << p1.m_age << endl;//类对象访问
cout << "p1年龄:" << Person::m_age << endl;//类名访问
}
int main()
{
//test1();
//test2();
system("pause");
return 0;
}
静态成员函数
#include<iostream>
using namespace std;
class Person
{
//静态成员函数
public:
static void func()
{
//静态成员函数只能访问静态成员变量
//id = 3;
m_age = 30;
cout << "this is func " <<m_age << endl;
}
static int m_age;
int id;
//静态成员函数的属性设置
private:
static void func2()
{
cout << "this is func2" << endl;
}
};
int Person::m_age = 0;//类外初始化
void test3()
{
Person p1;
p1.func();//类对象访问静态成员函数
Person::func();//类名访问静态成员函数
}
int main()
{
test3();
system("pause");
return 0;
}
这一块有个点不太清晰了,静态成员函数只能够访问静态成员变量,因为非静态成员变量不具有对象共享性
成员变量与成员函数分开存储
//成员函数和成员变量分开存储
#include<iostream>
using namespace std;
class Person
{
public:
static int m_age;//静态成员变量不属于类的对象
int m_age2;//非静态成员变量属于类的对象上,占4字节
static void func() {}//静态成员函数不属于类的对象
void func2() {}//非静态成员函数不属于类的对象上
};
void test1()
{
Person p1;//单个对象的字节大小为1
cout << sizeof(p1) << endl;
}
int main()
{
test1();
system("pause");
return 0;
}
5、this指针
指针指向调用成员函数的对象,this指向对象,则*this可解析出该对象,返回*this即返回对象
//this指针
#include<iostream>
using namespace std;
//this指针指向调用成员函数的对象,既然如此,返回对象本身可直接进行return *this
class Person
{
public:
Person(int age)
{
m_age = age;
}
Person& PersonAddAge(Person& p)
{
this->m_age += p.m_age;
return *this;//返回p1本体,采用引用接收
//如果采用值返回的方式,则拷贝构造一个新的变量,用新变量进行调用增加函数
}
int m_age;
};
void test1()
{
Person p1(18);
cout << "p1年龄:" << p1.m_age << endl;
Person p2(20);
//要求连续调用年龄增加函数,则使该函数返回一个p1即可,this指向p1,*this即可为p1
p1.PersonAddAge(p2).PersonAddAge(p2).PersonAddAge(p2);
cout << "p1年龄:" << p1.m_age << endl;
}
int main()
{
test1();
system("pause");
return 0;
}
空指针不可访问成员变量
//空指针不可访问成员变量
#include<iostream>
using namespace std;
class Person
{
public:
void showage()
{
if (this == NULL)
{
return; //保证代码的健壮性
}
//this指针默认存在,指向对象表示该对象的年龄,但是该对象为空
cout << this->m_age << endl;
}
int m_age = 10;
};
void test1()
{
Person* p = NULL;
}
int main()
{
test1();
system("pause");
return 0;
}
常函数与常对象
//常函数与常变量
#include<iostream>
using namespace std;
class Person
{
public:
//每个成员函数内部都有一个默认的this指针,指向调用该函数的对象,且指向一定不可改变
//但是指针指向的值可以改变,如果加上一个const则限制值也不可以改变
//如果设置一个可变变量,可无视const
void show() const
{
//m_age = 100;
m_height = 188;
}
int m_age;
mutable int m_height;
};
//常对象
void test1()
{
const Person p;//const限制为常对象
//p.m_age = 10;常对象不可更改非可变变量的值
p.m_height = 186;
p.show();//常对象只能调用常函数,因为普通函数内部可以修改变量,调用相当于侧面修改变量的值
}
int main()
{
system("pause");
return 0;
}