1.构造函数和析构函数。
2.构造函数的分类与调用。
#include <iostream>
using namespace std;
//对象的初始化和清理
class Person
{
public:
//1.构造函数,进行初始化操作
//没有返回值 不要写void
//函数名与类名相同
//构造函数可以有参数,可以发生重载
//创建对象的时候,构造函数会自动调用,而且只调用一次
Person()
{
cout << "Person无参构造函数的调用" << endl;
}
Person(int a)
{
age = a;
cout << "Person有参构造函数的调用" << endl;
}
//拷贝构造函数
Person(const Person& p)
{
//将传入的人身上所以属性,拷贝到我身上
age = p.age;
cout << "Person拷贝构造函数的调用" << endl;
}
//2.析构函数 进行清理的操作
//没有返回值 不写void
//函数名和类名相同 在名称前加~
//析构函数不可以有参数,不可以发生重载
//对象在销毁前,会自动调用析构函数,而且只会调用一次
~Person()
{
cout << "Person析构函数的调用" << endl;
}
int age;
};
//构造和析构都是必须有的实现,如果我们自己不提供,
//编译器会提供一个空实现的构造和析构
//调用
void test01()
{
//在栈上的数据,test01执行完毕后,释放这个对象
//1.括号法
Person p1;//默认构造函数调用
Person p2(10);//有参构造函数
Person p3(p2);//拷贝构造函数
//注意事项1
//调用默认构造函数时候,不要加(),编译器会认为是一个函数的声明
cout << "***************" << endl;
//2.显示法
Person p4;//默认构造函数调用
Person p5 = Person(10);//有参构造函数
Person p6 = Person(p2);//拷贝构造函数
//注意事项2
//Person(10) 匿名对象 特点:当前执行结束后,系统会立即回收掉匿名对象
//不要利用拷贝构造函数 初始化匿名对象
//3.隐式转换法
Person p7 = 10;//有参构造函数
Person p8 = p2;//拷贝构造函数
cout << "***************" << endl;
}
int main()
{
test01();
cout << "***************" << endl;
Person p;
system("pause");
return 0;
}
结果
Person无参构造函数的调用
Person有参构造函数的调用
Person拷贝构造函数的调用
***************
Person无参构造函数的调用
Person有参构造函数的调用
Person拷贝构造函数的调用
Person有参构造函数的调用
Person拷贝构造函数的调用
***************
Person析构函数的调用
Person析构函数的调用
Person析构函数的调用
Person析构函数的调用
Person析构函数的调用
Person析构函数的调用
Person析构函数的调用
Person析构函数的调用
***************
Person无参构造函数的调用
请按任意键继续. . .
3.浅拷贝与深拷贝。
#include <iostream>
using namespace std;
//浅拷贝与深拷贝
//浅拷贝:简单的赋值拷贝操作
//深拷贝:在堆区重新申请空间,进行拷贝操作
class Person
{
public:
Person()
{
cout << "Person无参构造函数的调用" << endl;
}
Person(int a,int b)
{
age = a;
height = new int(b);//栈区转入堆区
cout << "Person有参构造函数的调用" << endl;
}
//拷贝构造函数
Person(const Person& p)
{
//将传入的人身上所有属性,拷贝到我身上
age = p.age;
//height = p.height;//浅拷贝:错误
height = new int(*p.height);//深拷贝操作
cout << "Person拷贝构造函数的调用" << endl;
}
~Person()
{
cout << "Person析构函数的调用" << endl;
//析构代码,将堆区开辟数据做释放操作
if (height != NULL)
{
delete height;
height = NULL;
}
}
int age;
int* height;
};
//构造和析构都是必须有的实现,如果我们自己不提供,
//编译器会提供一个空实现的构造和析构
//调用
void test01()
{
//在栈上的数据,test01执行完毕后,释放这个对象
//1.括号法
Person p1;//默认构造函数调用
Person p2(10,150);//有参构造函数
cout << "p2的年龄为:" << p2.age << endl;
cout << "p2的身高为:" << *p2.height << endl;
Person p3(p2);//拷贝构造函数
cout << "p3的年龄为:" << p3.age << endl;
cout << "p3的身高为:" << *p3.height << endl;
//如果利用编译器提供的拷贝构造函数,会做浅拷贝操作
//浅拷贝带来的问题就是堆区的内存重复释放
//浅拷贝的问题要利用深拷贝进行解决
cout << "***************" << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
结果
Person无参构造函数的调用
Person有参构造函数的调用
p2的年龄为:10
p2的身高为:150
Person拷贝构造函数的调用
p3的年龄为:10
p3的身高为:150
***************
Person析构函数的调用
Person析构函数的调用
Person析构函数的调用
请按任意键继续. . .
4.静态成员变量。
5.静态成员函数。
#include <iostream>
using namespace std;
class Person
{
public:
//静态成员变量
//1 所有对象都共享一份数据
//2.编译阶段就分配内存
//3.类内声明,类外初始化操作
static int a;
//静态成员函数
static void func()
{
a = 50;//静态成员函数只可以访问静态成员变量
cout << "static void func调用" << endl;
}
int age;
int* height;
};
//类外初始化
int Person:: a = 100;
//调用
void test01()
{
Person p;
cout << p.a << endl;//100
Person p2;
p2.a = 200;
cout << p.a << endl;//200 所有对象都共享一份数据
//静态成员变量
//1.通过对象进行访问
cout << p.a << endl;
//2.通过类名进行访问
cout << Person::a << endl;//可以用这种方法,因为是静态变量,所有对象都共享一份数据
//静态成员函数
//1.通过对象进行访问
p.func();
//2.通过类名进行访问
Person::func();
}
int main()
{
test01();
system("pause");
return 0;
}
结果
100
200
200
200
static void func调用
static void func调用
请按任意键继续. . .
6.成员变量和成员函数分开存储。
#include <iostream>
using namespace std;
//成员变量和成员函数分开存储
class Person
{
};
class Person2
{
int a;//非静态成员变量
};
class Person3
{
static int b;//非静态成员变量
};
int Person3:: b = 0;
//调用
void test01()
{
Person p;
//C++会给每个空对象也分配一个字节空间,为了区分空对象占内存的位置
cout << "空对象的占用空间大小" << sizeof(p) << endl;//1
Person2 p2;
cout << "有一个非静态成员变量的占用空间大小" << sizeof(p2) << endl;//4
Person3 p3;
cout << "有一个静态成员变量的占用空间大小" << sizeof(p3) << endl;//1
//静态成员变量不属于类对象上,静态成员函数也同理
}
int main()
{
test01();
system("pause");
return 0;
}
结果
空对象的占用空间大小1
有一个非静态成员变量的占用空间大小4
有一个静态成员变量的占用空间大小1
请按任意键继续. . .
7.this指针的用途。
#include <iostream>
using namespace std;
//this指针的用途
class Person
{
public:
//1.解决名称冲突
Person(int age)
{
//this指针指向的是被调用的成员函数所属的对象
this->age = age;
}
void PersonAdd(Person& p)
{
this->age += p.age;
}
//2.返回对象本身用*this
Person& PersonAdd02(Person& p)
{
this->age += p.age;
return *this;
}
int age;
};
//1.解决名称冲突
void test01()
{
Person p1(18);
cout << p1.age << endl;
}
void test02()
{
Person p2(18);
cout << p2.age << endl;
Person p3(10);
p3.PersonAdd(p2);
cout << p3.age << endl;
}
//2.返回对象本身用*this
void test03()
{
Person p4(18);
cout << p4.age << endl;
Person p5(10);
//链式编程思想
p5.PersonAdd02(p4).PersonAdd02(p4).PersonAdd02(p4);
cout << p5.age << endl;
}
int main()
{
test01();
cout << "****************" << endl;
test02();
cout << "****************" << endl;
test03();
system("pause");
return 0;
}
结果
18
****************
18
28
****************
18
64
请按任意键继续. . .
8.空指针访问成员函数。
#include <iostream>
using namespace std;
//空指针访问成员函数
class Person
{
public:
void showName()
{
cout << "this a person class" << endl;
}
void showAge()
{
cout << "age = " << m_age << endl;
}
void showAge02()
{
if (this == NULL)
{
return;
}
cout << "age = " << m_age << endl;
}
int m_age;
};
void test01()
{
Person* p = NULL;
p->showName();//正常
//p->showAge();//出错,空指针不能访问成员变量
p->showAge02();//正常,推荐加一个if语句防止空指针
}
int main()
{
test01();
system("pause");
return 0;
}
9.const修饰成员函数。
#include <iostream>
using namespace std;
//const修饰成员函数
class Person
{
public:
//常函数
//this指针的本质是指针常量,指针的指向是不可以修改的
//在成员函数后加const,修饰的是this指针
void showAge() const
{
//this->m_age = 100;//错误 常函数中指针的值也不能修改
//this = NULL;//错误 常函数中指针的指向不能修改
this->x = 100;//成功
cout << "age = " << m_age << endl;
}
void func()
{
cout << "xxxxxxx " << endl;
}
int m_age;
mutable int x;//特殊变量,即使在常函数中,也可以修改这个值
};
//调用
void test01()
{
Person p;
p.showAge();
cout << p.m_age << endl;//普通对象可以调用常函数
}
void test02()
{
//常对象
const Person p2;
//p2.m_age = 100;//失败 常对象不能修改普通的成员变量+
p2.x = 10;//成功 特殊变量,在常对象下也可以修改
//p2.func();//失败 常对象不能调用普通函数
p2.showAge();//成功 常对象只能调用常函数
}
int main()
{
test01();
test02();
system("pause");
return 0;
}