一、面向对象
面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。
面向对象是相对于面向过程来讲的,面向对象方法,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式。
C++面向对象编程思想包含三大特性:封装、继承、多态。
C++认为万事万物皆为对象,对象上有属性和行为。
二、封装
(一)含义:将属性和行为作为一个整体来表现一个对象。可将属性和行为加以权限控制。C++中对象的封装方法有类和结构体:class和struct。
(二)权限:封装后对象的成员属性和成员函数可以添加权限控制;权限分为private(私有)、public(公共)、protected(保护)三种。
类中默认的成员属性和成员函数都是private(私有)权限,而结构体中成员属性和成员函数默认权限为public(公共),这也是C++中类和结构体唯一区别。
private:类内可以访问,类外不可访问。
public:类内外都可访问。
protected:类内可以访问,类外不可访问;但子类内可以访问。
三、类(关键字:class)
(一)语法:class+类名{......};
class Person{
private:
string m_Name;
int m_Age;
public:
string get_m_Name(){
return m_Name;
}
int get_m_Age(){
return m_Age;
}
};
(二)类的构造函数和析构函数
class ClassName{
public:
ClassName();//构造函数
~ClassName();//析构函数
}
-
构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。
-
析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理或保存工作。
这两个函数将会被编译器自动调用,完成对象初始化和清理工作。对象的初始化和清理工作是编译器强制要我们做的事情,因此如果我们不提供构造和析构,编译器会提供。编译器提供的构造函数和析构函数是空实现。
构造函数语法:类名(){}
-
构造函数,没有返回值也不写void
-
函数名称与类名相同
-
构造函数可以有参数,因此可以发生重载
-
程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次
1、默认构造函数:不需要参数。当类内未重构构造函数时,编译器默认提供。且无任何功能。实例化方法:Person p;
2、带参构造函数:需要参数。当类内未重构带参构造函数时,编译器默认提供,参数顺序按照类中成员变量声明顺序逐一提供,实例化方法:Person p={"张三",18};
3、拷贝构造函数:以类对象为参数,编译器默认提供。实例化方法: Person p1(p); Person p2=Person(p1); Person p3=p2;
- 拷贝构造函数分为浅拷贝和深拷贝。
- 浅拷贝:将参数对象的成员属性直接赋值给目标对象的成员属性,当成员属性中含有指针的情况,会造成两个对象内的指针成员变量指向同一块内存,其中一个对象销销毁后,另一个对象无法正常使用,程序会出现未知错误。
- 深拷贝:当类中成员变量含有指针,深拷贝让目标对象的成员指针指向一块新的空间,将参数对象中指针成员变量指向内存中储存的值,赋值到这块新空间。两个对象中指针成员变量指向不同的两个地址,但指向相同的值。
- 编译器默认的拷贝构造函数是浅拷贝,重构拷贝构造函数,需要使用深拷贝,避免程序出错。
4、构造函数的重构
class Person{
public:
string m_Name;
int m_Age;
Perspn(){};//默认构造函数
Person(string name,int age){//带参构造函数
m_Name=name;
m_Age=age;
}
Person(Person p){ //拷贝构造函数
m_Name=p.m_Name;
m_Age=p.m_Age;
}
}
- 当类中对带参构造函数自定义,编译器将不再提供默认的不带参数构造函数,但仍然会提供拷贝构造函数。
- 当类中对拷贝构造函数自定义,编译器将不再提供默认的前两种构造函数。
5、类的实例化方法
(1)括号法,常用
Person p1(10);
//注意1:调用无参构造函数不能加括号,如果加了编译器认为这是一个函数声明
//Person p2();
(2) 显式法
Person p2 = Person(10);
Person p3 = Person(p2);
//Person(10)单独写就是匿名对象 当前行结束之后,马上析构
(3)隐式转换法
Person p4 = 10; // Person p4 = Person(10);
Person p5 = p4; // Person p5 = Person(p4);
//注意2:不能利用 拷贝构造函数 初始化匿名对象 编译器认为是对象声明。Person (p5);//二义性
6、类的析构函数
析构函数语法: ~类名(){}
-
析构函数,没有返回值也不写void
-
函数名称与类名相同,在名称前加上符号 ~
-
析构函数不可以有参数,因此不可以发生重载
-
程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次
(三)构造函数的初始化列表
构造函数初始化成员变量时有一种列表初始化方法,语法如下:
- 不带参构造函数,列表初始化:
ClassName():变量1(初始化值1),变量2(初始化值2).....{}
- 带参构造函数,列表初始化:
ClassName(初始化值1,初始化值2...):变量1(初始化值1),变量2(初始化值2).....{}
tips1:据说使用初始化列表初始化成员变量的速度要比在构造函数内初始化成员变量速度快。
tips2:使用列表初始化成员变量的顺序,和成员变量声明顺序一致,和列表中的顺序无关。
#include<iostream>
using namespace std;
class Person {
public:
Person():m_Name("张三"),m_Age(18){
cout << "不带参构造函数,使用列表初始化成员变量" << endl;
}
Person(string name, int age) :m_Name(name), m_Age(age) {
cout << "带参构造函数,使用列表初始化成员变量" << endl;
}
string m_Name;
int m_Age;
void show() {
cout << "姓名:" << m_Name << endl;
cout << "年龄:" << m_Age << endl;
}
};
void test01() {
Person p;
p.show();
Person p1("lisi", 20);
p1.show();
}
int main(int argc, char const **argv) {
test01();
return 0;
}