类的声明和实现是分开做的,在头文件中生命类的属性和函数,在cpp文件中实现函数具体业务。
Teacher.h
#pragma once
class Teacher
{
private:
char name[20];
int age;
public:
void setAge(int _age);
int getAge();
};
Teacher.cpp
#include "Teacher.h"
void Teacher::setAge(int _age) {
age = _age;
}
int Teacher::getAge() {
return age;
}
当类中没有声明构造函数和复制构造函数,编译器会提供默认的空构造函数和默认的复制构造函数,提供的默认的构造函数只是浅拷贝,简单的成员变量复制。
当类中定义了复制构造函数后,编译器不在提供空构造函数。
当类中定义了有参构造函数后,编译器不在提供空构造函数。
当类中提供了构造函数或复制构造函数,编译器就不再提供空构造函数或默认的复制构造函数。
当类中提供了有参构造函数,C++编译器不再提供构造函数。
class Teacher
{
public:
//....省略
//复制构造
Teacher(const Teacher& t) {
cout << "Teacher 复制构造函数执行" << endl;
}
};
int main() {
Teacher teacher01(2);
Teacher teacher02 = teacher01;
cout << teacher02.age << endl;//打印:-858993460,重写了复制构造函数,但是没有其他操作,所以打印垃圾值
system("pause");
return 0;
}
但是如果不重写复制构造函数,编译器会帮我们实现复制构造函数,执行的结构就是teacher02.age = 2,且这里teacher02对象不会执行构造函数,只会执行他的复制构造函数。
对象创建时执行,先创建的对象先构造
//无参构造
Teacher();
//有参构造
Teacher(int a);
//复制构造函数(copy构造函数)
Teacher(const Teacher &teacher);
class Teacher
{
public:
int age;
//无参构造
Teacher() {
cout << "Teacher 无参构造函数执行" << endl;
}
//有参构造
Teacher(int a) {
cout << "Teacher 有参构造函数执行 a : " << a << endl;
}
};
int main() {
//==================无参构造调用=======================
Teacher teacher01;//打印结果:Teacher 无参构造函数执行
//==================有参构造调用=======================
//调用有参构造函数,这里的等号已经不是赋值运算,C++对等号功能进行了扩展
Teacher teacher02 = 2;//打印结果:Teacher 有参构造函数执行 a : 2
//等价Teacher teacher02 = 3。因为等号右侧是括号表达式,最后一个值是结果
Teacher teacher03 = (2, 3);//打印结果:Teacher 有参构造函数执行 a : 3
Teacher teacher04(4);//打印结果:Teacher 有参构造函数执行 a : 4
system("pause");
return 0;
}
作用:用一个对象去初始化另一个对象。
复制构造函数声明:Teacher(const Teacher &teacher)
方式一:
Teacher teacher01(2);
Teacher teacher02 = teacher01;
方式二:
Teacher teacher01(2);
Teacher teacher02(teacher01);//Teacher 复制构造函数执行
方式三:
void fun(Teacher t) {
cout << "fun t.age : "<< t.age << endl;
}
int main() {
Teacher teacher01(2);//打印结果:Teacher 有参构造函数执行 a : 2
fun(teacher01);//打印结果:Teacher 复制构造函数执行
system("pause");
return 0;
}
fun函数调用时,会将teacher01拷贝一份复制给fun的参数,所以也会执行复制构造函数
方式四:
Teacher fun() {
Teacher teacher01(2);
cout << "fun()函数创建teacher01对象" << endl;
//用teacher01对象创建了一个匿名对象返回
return teacher01;//fun函数执行完后teacher01对象释放
}
void test() {
fun();//fun返回的匿名对象没有使用,所以当test函数执行完,匿名对象也要释放
cout << "test()执行完毕" << endl;
}
int main() {
test();
system("pause");
return 0;
}
打印结果:
Teacher 有参构造函数执行 a : 2
fun()函数创建teacher01对象
Teacher 复制构造函数执行
Teacher 析构构造函数执行
Teacher 析构构造函数执行
test()执行完毕
执行流程:
01.创建teacher01对象 >>> 02.将teacher01对象初始化一个匿名对象 >>> 03.fun函数执行结束后会释放teacher01对象 >>> 04.fun()函数返回值没有对象接受,所以也得释放匿名对象。
结论:函数返回的是一个元素(复杂类型),返回的是一个新的匿名对象,所以会调用匿名对象的类的复制构造函数。
如果fun()函数返回值有对象接受执行结果就不同了。
Teacher fun() {
Teacher teacher01(2);
cout << "fun()函数创建teacher01对象" << endl;
return teacher01;
}
void test() {
Teacher teacher = fun();//teacher接受fun函数返回的匿名对象
cout << "test()执行完毕" << endl;
}
int main() {
test();
system("pause");
return 0;
}
fun()返回值由teacher对象接受,C++编译器直接把匿名对象转成teacher,从无名转成有名,所以此处没有执行复制构造函数,匿名对象在test函数执行完也会释放,打印结果对比如下图:
fun()返回值赋值给teacher对象,匿名对象会被释放,所以test函数执行完要多释放一个对象,打印结果对比如下图:
备注:上面打印截图“赋值构造函数执行”写错了,应是“复制构造函数执行”。这里一定要分清楚复制和赋值的区别。
函数返回的匿名对象去留总结:
“==”在不同的场景有不同的含义:
int main() {
Teacher teacher01(2);//打印:Teacher 有参构造函数执行 a : 2
//此处等号是用teacher01初始化teacher02
Teacher teacher02 = teacher01;//打印:Teacher 复制构造函数执行
Teacher teacher03(3);//打印:Teacher 有参构造函数执行 a : 3
teacher03 = teacher01;//此处等号是将teacher01赋值给teacher03
system("pause");
return 0;
}
对象销毁时执行,先创建的对象后析构
举例:
Teacher.h
class Teacher
{
private:
char name[20];
int age;
public:
Teacher();//构造函数声明
~Teacher();//析构函数
void setAge(int _age);
int getAge();
};
Teacher.cpp
void Teacher::setAge(int _age) {
cout << "Teacher setAge函数执行" << endl;
age = _age;
}
int Teacher::getAge() {
cout << "Teacher getAge函数执行" << endl;
return age;
}
Teacher::Teacher() {
cout << "Teacher 构造函数执行" << endl;
}
Teacher::~Teacher() {
cout << "Teacher 析构函数执行" << endl;
}
test.cpp
//teacher是一个局部变量,函数执行完就会释放
void objTest() {
cout << "声明Teacher befor" << endl;
Teacher teacher;
cout << "声明Teacher after" << endl;
teacher.setAge(10);
cout << "age : " << teacher.getAge() << endl;//age : 10
}
int main() {
objTest();
system("pause");
return 0;
}
执行结果
声明Teacher befor
Teacher 构造函数执行
声明Teacher after
Teacher setAge函数执行
Teacher getAge函数执行
age : 10
Teacher 析构函数执行
用Teacher teacher
生命对象的时候就会执行构造函数,在函数objTest()执行结束后teacher会释放内存,会执行析构函数。
struct在C++中进行了加强,可以和class具有一样的功能。
默认struct访问权限是public,默认class访问权限是private
struct MyStruct
{
int age;
};
class MyClass
{
int age;
};
int main() {
MyStruct mystr;
MyClass cls;
mystr.age = 20;//编译成功,默认struct访问权限是public
cls.age = 20;//编译报错,默认class访问权限是private
system("pause");
return 0;
}
备注:代码自动格式化:Ctrl+K+F键(按住Ctrl键,先按下K键再按下F键)