C++ 面向对象-class的基本使用
本文最后更新于:2022年4月22日 上午
C++ 面向对象-class的使用
C++
中也有面向对象(oop
) 的概念,面向对象的三大特性是 封装,继承,多态 ,基本上大学都会学习面向对象思想,这里我们先从最基本的语法开始学习,会涉及到封装 后续再更新继承与多态,因为多态的前提是继承,所以后面会先学习继承,再学习多态 。
通过 class
关键字来创建一个类,类里面可以通过以下三个关键字来修饰 属性或者方法
public 公共属性,类内部,派生类,实例都可以访问
private 私有属性,类内部才可以访问
protected 类内部和派生类可以访问,实例不可以访问
类的定义
以下定义了一个最基本的 Person
类,并且定义了两个公共属性
class Person {
public:
string name;
int age;
}
类的基本使用
class Person {
public:
string name;
int age;
}
int main() {
// 类的基本使用 和 struct 使用起来差不多
Person p1;
p1.name = "小明";
p1.age = 18;
}
封装
我们通过 private
关键字进行修饰,然后编写对应的 getter
和 setter
方法来对这些私有属性进行赋值与获取。
class Person2 {
// 私有的
private:
string name;
int age;
// 通过 get/set 来操作私有属性
public:
void setName(string props_name) {
name = props_name;
}
string getName() {
return name;
}
void setAge(int props_age) {
age = props_age;
}
int getAge() {
return age;
}
};
int main() {
// 封装 getter 和 setter
Person2 p2;
p2.setName("小红");
p2.setAge(18);
}
输出
小红
18
class 和 struct 的区别
从使用的角度来看,class
和 struct
没有什么区别
// 默认的权限是 private
class Person {
string name;
int age;
};
struct Student {
string name;
int age;
};
int main() {
Person3 p3;
// 语法报错,不允许设置
//p3.name = "小红";
//p3.age = 18;
// 相当于是 public 权限
Student s1;
s1.name = "小李";
s1.age = 19;
return 0;
}
class 基本案例
计算两个立方体的体积是否一致
#include <iostream>;
using namespace std;
class Cube {
private:
int length;
int width;
int height;
public:
void setLength(int len) {
length = len;
}
int getLength() {
return length;
}
void setWidth(int w) {
width = w;
}
int getWidth() {
return width;
}
void setHeight(int h) {
height = h;
}
int getHeight() {
return height;
}
// 计算面积
int calcArea() {
return length * width;
}
// 计算体积
int calcVolume() {
return length * width * height;
}
// 比较两个立方体是否相同
bool isSomeCube(Cube c) {
if (height == c.getHeight()
&& width == c.getWidth()
&& length == c.getLength()
) {
return true;
}
return false;
}
};
// 比较两个立方体是否相同
bool isSomeCule(Cube& c1, Cube& c2) {
if (c1.getHeight() == c2.getHeight()
&& c1.getWidth() == c2.getWidth()
&& c1.getLength() == c1.getLength()
) {
return true;
}
return false;
}
int main() {
/*
案例一:计算两个立方体是否相同
*/
Cube c1;
c1.setHeight(10);
c1.setLength(10);
c1.setWidth(10);
cout << "c1 面积:" << c1.calcArea() << endl;
cout << "c1 体积:" << c1.calcVolume() << endl;
Cube c2;
c2.setHeight(10);
c2.setLength(10);
c2.setWidth(10);
cout << "c2 面积:" << c1.calcArea() << endl;
cout << "c2 体积:" << c1.calcVolume() << endl;
cout << "全局方法比较 c1 和 c2 是否一致:" << isSomeCule(c1, c2) << endl;
cout << "实例方法比较 c1 和 c2 是否一致:" << c1.isSomeCube(c2) << endl;
system("pause");
return 0;
}
输出
c1 面积:100
c1 体积:1000
c2 面积:100
c2 体积:1000
全局方法比较 c1 和 c2 是否一致:1
实例方法比较 c1 和 c2 是否一致:1
如果我们将上述代码简单的进行一下修改
Cube c1;
c1.setHeight(10);
c1.setLength(10);
c1.setWidth(10);
cout << "c1 面积:" << c1.calcArea() << endl;
cout << "c1 体积:" << c1.calcVolume() << endl;
Cube c2;
c2.setHeight(10);
c2.setLength(10);
c2.setWidth(20);
cout << "c2 面积:" << c1.calcArea() << endl;
cout << "c2 体积:" << c1.calcVolume() << endl;
cout << "全局方法比较 c1 和 c2 是否一致:" << isSomeCule(c1, c2) << endl;
cout << "实例方法比较 c1 和 c2 是否一致:" << c1.isSomeCube(c2) << endl;
输出
c1 面积:100
c1 体积:1000
c2 面积:100
c2 体积:1000
全局方法比较 c1 和 c2 是否一致:0
实例方法比较 c1 和 c2 是否一致:0
类的分文件编写
我们会发现,在上面,我们所有的代码都是写在一个文件里面的,当代码多起来后维护起来会很困难,所以我们分文件编写,和之前的 函数的分文件编写差不多,如下所示
|- 头文件
|- person.h
|- 源文件
|- person.cpp
|- main.cpp
person.h
#pragma once
#include <iostream>;
using namespace std;
#include "phone.h"
class Person {
private:
string name;
int age;
public:
Phone phone;
void setName(string name);
string getName();
void setAge(int age);
int getAge();
void setPhone(Phone pPhone);
Phone getPhone();
void sayName();
void sayAge();
void sayBrand();
};
class
的声明与实现分开时,在写实现时需要通过 XXX::xx
的语法表示实现的哪一个方法
person.cpp
#include "person.h";
#include "phone.h";
void Person::setName(string pName) {
name = pName;
}
string Person::getName() {
return name;
}
void Person::setAge(int pAge) {
age = pAge;
}
int Person::getAge() {
return age;
}
void Person::setPhone(Phone pPhone) {
cout << pPhone.brand << endl;
phone = pPhone;
}
Phone Person::getPhone() {
return phone;
}
void Person::sayName() {
cout << "我的姓名是:" << name << endl;
}
void Person::sayAge() {
cout << "我的年龄是:" << age << endl;
}
void Person::sayBrand() {
cout << "我的手机是:" << phone.brand << endl;
}
phone.h
#pragma once
#include <iostream>;
using namespace std;
class Phone {
public:
string brand;
};
main
#include <iostream>;
using namespace std;
#include "person.h";
#include "phone.h";
// 类的嵌套,以及类的分文件编写
int main() {
Person p;
p.setName("小明");
p.setAge(18);
Phone phone;
//phone.setBrand("华为");
phone.brand = "华为";
p.setPhone(phone);
cout << "名字:" << p.getName() << endl;
cout << "年龄:" << p.getAge() << endl;
cout << "手机:" << p.getPhone().brand << endl;
p.sayName();
p.sayAge();
p.sayBrand();
system("pause");
return 0;
}
构造函数&析构函数
构造函数
和很多语言一样,C++
也有构造函数,会在实例化对象的时候调用,所有的 class
都有构造函数,如果没有手动编写的话默认编译器会帮我默认生成一个空实现(内部没有任何代码)的构造函数
与类同名,不需要写 返回值类型,也不允许
return
可以重载
析构函数
会在函数销毁的时候调用(类似于 vue
生命周期中的 beforeDistory
)
- ~开头,后面与类名同名,不允许重载,没有返回值
编写 构造函数和析构函数时都需要使用
public
关键字进行修饰
构造的分类
- 按照参数进行分类
    1. 无参构造函数(默认构造函数)
    2. 有参构造函数
- 按照类型分类
    1. 普通构造函数
    2. 拷贝构造函数
无参构造函数(默认构造函数) 的基本使用
如下代码 创建p1
时会调用 Person
的默认构造函数,虽然没有手动写,但是编译器会默认帮我们提供一个
class Person {
public:
string name;
// 默认构造函数
Person() {
cout << "Person 默认构造函数被调用" << endl;
}
~Person() {
cout << name <<": Person 析构函数被调用" << endl;
}
};
// ...
Person P1;
P1.name = "小明";
输出
Person 默认构造函数被调用
小明: Person 析构函数被调用
有参构造函数
当我们需要在创建对象时同时传入一些参数的话,就可以使用有参构造函数了
class Person {
public:
string name;
// 默认构造函数
Person() {
cout << "Person 默认构造函数被调用" << endl;
}
// 有参构造函数
Person(string pName) {
cout << "Person 有参构造函数被调用" << endl;
name = pName;
}
~Person() {
cout << name <<": Person 析构函数被调用" << endl;
}
};
// ...
Person p1("小明");
cout << "名称:" << p1.name << endl;
输出
Person 有参构造函数被调用
名称:小明
小明: Person 析构函数被调用
拷贝构造函数
在 C++
中还有拷贝构造函数的概念,可以用来拷贝一个相同的对象,如果不写的话,编译器默认也会提供一个
class Person {
public:
string name;
// 默认构造函数
Person() {
cout << "Person 默认构造函数被调用" << endl;
}
// 有参构造函数
Person(string pName) {
cout << "Person 有参构造函数被调用" << endl;
name = pName;
}
Person(const Person& p) {
cout << "Person 拷贝构造函数被调用" << endl;
name = p.name;
}
~Person() {
cout << name <<": Person 析构函数被调用" << endl;
}
};
// ...
Person p1("小明");
Person p2(p1);
cout << "p2 姓名:" << p2.name << endl;
输出
Person 有参构造函数被调用
Person 拷贝构造函数被调用
p2 姓名:小明
小明: Person 析构函数被调用
小明: Person 析构函数被调用
构造函数的三种调用方式
在 C++
中,构造函数有三种调用的方式,也就是说其实我们可以通过三种方式来实例化对象
方式一
Person p;
Person p2("小明");
方式二
Person p3 = Person();
Person p4 = Person("小明");
方式三 (隐式转换方式)
string name = "小明";
Person p5 = name;
注意:方式一中调用默认构造函数不可以加上小括号() ,如果加上小括号会被编译器当成是 方法的声明如:
Person p()
构造函数的三个执行时机
实例化对象时的基本使用
Person p1("小明");
Person p2(p1);
输出
Person 有参构造函数被调用
Person 拷贝构造函数被调用
对象作为函数参数时使用
void doWork(Person p) {
}
// ...
// 接上述代码继续使用
doWork(p2);
输出
Person 拷贝构造函数被调用
小明: Person 析构函数被调用
作为函数的返回值使用
Person doWork2() {
// 这里会执行两次构造函数,第一次为 定义p,第二次为返回 p 的时候
Person p("小明");
return p;
}
// ...
doWork2();
输出
Person 有参构造函数被调用
Person 拷贝构造函数被调用
这里也可以把修改一下上述代码,让它只执行一次,如下
Person doWork2() {
return Person p("小明");
}
输出
Person 有参构造函数被调用
构造函数执行时机的完整示例
// 作为函数参数
void doWork(Person p) {
}
// 作为函数返回值
Person doWork2() {
return Person("小明");
}
// ...
// 1. 基本使用
Person p1("小明");
Person p2(p1);
cout << "------------------" << endl;
// 2. 作为函数参数
doWork(p2);
// 3. 函数的返回值
cout << "------------------" << endl;
doWork2();
输出
Person 有参构造函数被调用
Person 拷贝构造函数被调用
------------------
Person 拷贝构造函数被调用
小明: Person 析构函数被调用
------------------
Person 有参构造函数被调用
小明: Person 析构函数被调用
小明: Person 析构函数被调用
小明: Person 析构函数被调用
总结
上述是 class
在 C++
中的基本使用,掌握以上语法后,就已经可以编写一些基本的案例了,需要注意的是 构造函数的几种调用方式,以及 普通构造函数与拷贝构造函数的区别,析构函数的执行时机,C++
的面向对象还有很多需要掌握的知识,后续再慢慢进行记录更新吧
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议,转载请注明出处。