类的定义
C++ 在 C 语言的基础上增加面向对象编程,类是用于指定对象的形式,是一种用户自定义的数据类型,封装了数据和函数。类可以被看作是一种模板,可以用来创建具有相同属性和行为的多个对象。
- class 关键字定义类,相当于在结构体中加入方法;
- 花括号内定义成员变量、成员方法,并且分块表示,每块使用public/private/protected关键字修饰
- 最后以分号结束
- 访问修饰符
- public,公有访问,最大的访问权限,对象可以直接调用属性、方法;
- protected,受保护的访问,只能在类内部访问(或友元函数),对象无法直接调用;可以被子类继承,并在子类内部访问;
- private, 私有访问,只能在类内部访问(或友元函数),对象无法直接调用;可以被子类继承,但子类内部也无法访问
- 使用冒号表示继承;
- class Dog : public Animal { }; 公有继承,访问权限不变,基类的public、protected、private仍保持不变;
- class Dog : protected Animal { }; 受保护的继承,基类的public、protected、private变为protected、protected、private
- class Dog : private Animal { }; 私有继承,继承下来的全部为私有访问权限,基类的public、protected、private变为private、private、private
类定义案例
#include <iostream>
#include <string>
#include <math.h>
using namespace std;
// 类的声明 一般在头文件
class Stu {
public: // 公有权限 接口
const string& getName() const { // const 表示常量成员函数 (只读,不会改变实例对象的任何数据)
return name; // this指针指向当前实例对象,可以省略 this->name;
// 返回name的常量引用,避免值拷贝的内存消耗
}
void setName(const string& name) {
// 直接访问当前对象 的属性
this->name = name;
}
private: // 数据放在 私有访问 块
string name;
};
int main() {
// 创建对象
Stu stu;
// 设置名字
stu.setName("jack");
string name = stu.getName();
cout << "got name:" << name << endl;
return 0;
}
构造函数
- 与类名相同,无返回值;
- 创建对象时,对其成员变量进行初始化,成员变量必须初始化后才可以使用;
- this指针初始化
- 初始化列表来初始化
- 未定义构造函数时,编译器默认会定义一个无参构造;
- 定义构造函数时,需从无参构造开始
重载
(即参数列表不同的同名函数);此时编译器不再默认定义无参构造; - 实例化对象
- B b; 走无参构造
- B b(a, b); 走有参构造
- B* ptr = new B; 走无参构造,动态分配内存(堆内存)
- B* ptr = new B(a, b); 走有参构造,动态分配内存注意 delete ptr 释放
#include <iostream>
#include <string>
#include <math.h>
using namespace std;
// 类的声明 一般在头文件
class Stu {
public: // 公有权限 接口
Stu() { // 无参构造函数,无返回值
cout << "创建对象时,初始化对象" << endl;
};
// 重载构造函数(参数列表不同)
Stu(const string& name) {
this->name = name; // this指针初始化
}
// 列表初始化
Stu(const string& name, const int& age): name(name), age(age){
cout << "列表初始化" << endl;
// 相当于
// this->name = name;
// this->age = age;
}
const string& getName() const { // const 表示常量成员函数 (只读,不会改变实例对象的任何数据)
return name; // this指针指向当前实例对象,可以省略 this->name;
// 返回name的常量引用,避免值拷贝的内存消耗
}
void setName(const string& name) {
// 直接访问当前对象 的属性
this->name = name;
}
private: // 数据放在 私有访问 块
string name;
};
int main() {
// 创建对象
Stu stu("lauf");
string name = stu.getName();
cout << "got name:" << name << endl;
return 0;
}
拷贝构造函数
- 编译器默认会定义拷贝构造函数;
- 类中有指针变量,且需动态分配内存时,必须定义拷贝构造函数;
- 同构造函数一样,形参常为类的对象的引用;
- 使用场景:
- 使用引用的对象来初始化一个新对象;
- 函数传参对象(复制对象)、函数返回对象(复制对象);
- 注意传对象的引用,不会触发拷贝;
- 场景:使用一个已创建的对象初始化一个新对象;
#include <iostream>
#include <string>
#include <math.h>
using namespace std;
// 类的声明 一般在头文件
class Stu {
public: // 公有权限 接口
Stu() { // 无参构造函数,无返回值
cout << "创建对象时,初始化对象" << endl;
this->ptr = new int; // 为指针动态分配内存
*(this->ptr) = 0;
};
// 拷贝 构造函数
Stu(const Stu& stu) {
// stu为被拷贝的对象
cout << "被拷贝的对象:" << *(stu.ptr) << endl;
*(this->ptr) = *(stu.ptr);
}
void setVal(const int& val) {
*ptr = val;
}
void printVal() const {
cout << *ptr << endl;
}
private: // 数据封装在私有访问块
int* ptr; // 包含指针,且需要动态分配内存
};
int main() {
// 创建对象
Stu s1;
s1.setVal(20);
Stu s2 = s1; // 使用s1对象初始化 s2, s1是被拷贝的对象,s2为this指向的对象
s2.printVal();
return 0;
}
- 场景:函数传参、返回对象,复制对象;
#include <iostream>
using namespace std;
// 类的声明 一般在头文件
class Stu {
public: // 公有权限 接口
Stu() { // 无参构造函数,无返回值
cout << "创建对象时,初始化对象" << endl;
this->ptr = new int; // 为指针动态分配内存
*(this->ptr) = 0;
};
// 拷贝 构造函数
Stu(const Stu& stu) {
// stu为被拷贝的对象
cout << "被拷贝的对象:" << *stu.ptr << endl;
// 拷贝时,会自动创建一个新对象,这里仅为其指针变量分配内存,并初始化
ptr = new int; // 动态分配内存
*ptr = *stu.ptr; // 初始化值
}
void setVal(const int& val) {
*ptr = val;
}
void printVal() const {
cout << *ptr << endl;
}
private: // 数据封装在私有访问块
int* ptr; // 包含指针,且需要动态分配内存
};
void printObj(Stu stu) { // 值传递,拷贝对象(执行拷贝构造函数)
stu.printVal();
}
int main() {
// 创建对象
Stu s1;
s1.setVal(20);
printObj(s1);
return 0;
}
析构函数
- 删除一个对象时,执行的函数,通常用于指针内存释放、文件的关闭等;
- ~类名,无参、无返回;
#include <iostream>
using namespace std;
// 类的声明 一般在头文件
class Stu {
public: // 公有权限 接口
Stu() { // 无参构造函数,无返回值
cout << "创建对象时,初始化对象" << endl;
this->ptr = new int; // 为指针动态分配内存
*(this->ptr) = 0;
};
// 析构函数,删除对象时,调用
~Stu() {
cout << "删除对象时执行" << endl;
delete ptr; // 释放内存
}
void setVal(const int& val) {
*ptr = val;
}
void printVal() const {
cout << *ptr << endl;
}
private:
int* ptr;
};
int main() {
// 创建对象
Stu s1; // 程序结束,自动删除s1对象
s1.setVal(20);
return 0;
}