(主要作用在于创建对象时为对象的成员属性赋值(无需手动调用))
语法:类名 (){}
在析构函数里面程序员手动释放堆区的数据
(主要作用在于对象销毁前系统自动调用,执行清理工作)
语法:~类名(){}
这两函数都由编译器自动调用,程序员不提供的话编译器会自己提供空实现的构造函数和析构函数
构造函数和析构函数通常都在public作用域中
有参构造函数、无参构造函数
普通构造函数、拷贝构造函数
拷贝构造函数:
class Person{//类名
Person(const Person &p){//拷贝构造函数|const是为了保护p不被修改
//自己属性 = p.属性名
}
};
(1)类名 对象名;//默认构造函数调用
这里不能加括号,加上括号后编译器会把这个当作函数声明
(2)类名 对象名(普通参数);//有参构造函数调用
(3)类名 对象名(对象参数);//拷贝构造函数调用
(1)类名 对象名;//默认构造函数调用
(2)类名 对象名 = 类名(参数);//有参构造调用
(3)类名 对象名 = 类名(对象参数);//拷贝构造函数调用
类名(参数);//匿名对象
不要用拷贝构造函数初始化匿名对象
(编译器会认为 类名(对象参数)等于 类名 对象名,会报错说重定义)
当匿名函数所在的行执行结束后,系统会立即回收匿名函数
(1)类名 对象名 = 参数;(相当于显示的(2))
(2)类名 对象名 = 对象参数;(相当于显示的(3))
1、使用一个已经创建完毕的对象来初始化一个新对象
2、值传递的方式来给函数参数传值
3、以值方式返回局部对象
class Person {
public:
Person() {//无参构造函数
mAge = 0;
}
Person(int age) {//有参构造函数
mAge = age;
}
Person(const Person& p) {//拷贝构造函数;
mAge = p.mAge;
}
//析构函数在释放内存之前调用
~Person() {//析构函数
}
public:
int mAge;
};
//1. 使用一个已经创建完毕的对象来初始化一个新对象
void test01() {
Person man(100); //p对象已经创建完毕
Person newman(man); //调用拷贝构造函数
Person newman2 = man; //拷贝构造
//Person newman3;
//newman3 = man; //不是调用拷贝构造函数,赋值操作
}
//2. 值传递的方式给函数参数传值
//相当于Person p1 = p;
void doWork(Person p1) {}
void test02() {
Person p; //无参构造函数
doWork(p);
}
//3. 以值方式返回局部对象
Person doWork2()
{
Person p1;
cout << (int *)&p1 << endl;
return p1;
}
void test03()
{
Person p = doWork2();
cout << (int *)&p << endl;
}
int main() {
//test01();
//test02();
test03();
system("pause");
return 0;
}
默认情况下,c++的编译器至少给一个类添加3个函数:
1、默认构造函数(无参,函数体为空)空实现
2、默认析构函数(无参,函数体为空)空实现
3、默认拷贝函数,对属性进行值拷贝 值拷贝
构造函数调用规则:
浅拷贝:简单的复制拷贝操作
深拷贝:在堆区重新申请空间,进行拷贝操作
利用编译器提供的拷贝构造函数是浅拷贝
浅拷贝的问题:对区内存重复释放
解决浅拷贝的问题:自己编写拷贝函数·,申请内存,即深拷贝
当成员变量有指针时要重写拷贝构造函数和析构函数
1、作用:C++提供了初始化列表语法,用来初始化属性
2、语法:构造函数():属性1(值1),属性2(值2)… {}
注意冒号
例如
class A {}
class B{
A a;
}
B类里面,用A的对象做类成员
先调用A类的构造函数后调用B的构造函数
先调用B类的析构函数后调用A的析构函数
1、定义在成员变量和成员函数前加上关键字static
2、分类:静态成员变量,静态成员函数
class Person
{
public:
static int m_A; //声明
};
int Person::m_A = 10;//初始化
静态成员变量可以通过对象名访问也可以通过类名进行访问
通过类名访问的语法是 类名::静态成员变量名
静态成员函数可以通过对象名访问也可以通过类名进行访问
静态成员变量也有访问权限
只有非静态成员变量才属于类的对象
class Person {
public:
Person() {
mA = 0;
}
//非静态成员变量占对象空间
int mA;
//静态成员变量不占对象空间
static int mB;
//函数也不占对象空间,所有函数共享一个函数实例
void func() {
cout << "mA:" << this->mA << endl;
}
//静态成员函数也不占对象空间
static void sfunc() {
}
};
//空对象占用空间为:1(为了区分不同的空对象占内存的位置)
//每个空对象也应该有一个独一无二的内存地址
int main() {
cout << sizeof(Person) << endl;
system("pause");
return 0;
}
(1)this指针指向被调用的成员函数所属的对象
this指针是隐含每一个非静态成员函数内的一种指针
this指针不需要定义,直接使用即可
(2)this指针的用途:
this指针是指针常量,不能修改指向,可以修改指针指向的值
class Person
{
public:
Person(int age)
{
//1、当形参和成员变量同名时,可用this指针来区分
this->age = age;
}
Person& PersonAddPerson(Person p)//返回值类型要用引用
{
this->age += p.age;
//返回对象本身
return *this;
}
int age;
};
void test01()
{
Person p1(10);
cout << "p1.age = " << p1.age << endl;
Person p2(10);
//链式编程思想
p2.PersonAddPerson(p1).PersonAddPerson(p1).PersonAddPerson(p1);
cout << "p2.age = " << p2.age << endl;
}
int main() {
test01();
system("pause");
return 0;
}
C++中空指针也是可以调用成员函数的,但是也要注意成员函数内部有没有用到this指针
如果用到this指针,需要加以判断保证代码的健壮性
class Person {
public:
void ShowClassName() {
cout << "我是Person类!" << endl;
}
void ShowPerson() {
if (this == NULL) {
return;//加上 return之后就可以用空指针调用这个函数了
}
cout << mAge << endl;
}
public:
int mAge;
};
void test01()
{
Person * p = NULL;
p->ShowClassName(); //空指针,可以调用成员函数
p->ShowPerson(); //但是如果成员函数中用到了this指针,就不可以了
}
int main() {
test01();
system("pause");
return 0;
}
补充:
函数的()后面加const表示此时函数里使用的this指针不能改变指向,也不能改变指向的值