C++面向对象的三大特性:封装、继承、多态
封装
封装的意义: 将类中的属性和行为看成一个整体,用来表示事物; 对属性和行为的权限加以约束
类的设计: 语法: class 类名 { 权限 ; 属性 / 行为 };
class Person
{
public:
int m_A // 属性
void test() // 行为
{
cout << m_A << endl;
}
};
类中的访问权限有三种:
(1)public 公共权限: 类外类内都可以访问
(2)protected 保护权限: 类内可以访问,类外不可以访问
(3)private 私有权限: 类内可以访问,类外不可以访问
protected 和 private的区别在于: protected 儿子可以访问父亲的保护权限 ;而private 儿子不可以访问父亲的私有权限。
class Person
{
public:
int m_name;
protected:
string lover;
private:
int password;
public:
void test()
{
m_name = "张三“;
lover = "张 " ;
password = 123456;
}
};
void test()
{
Person p1;
cout << p1.m_name << endl; // 可以访问
p1.password;
p1.lover ; // 不可以访问 因为private 和 public 权限不允许在类外访问
}
在C++中 struct 和 class 的区别是: 默认访问权限不同, class 默认私有权限; struct 默认公共权限。
成员属性私有化:可以控制属性和行为的读写权限;对于写权限可以检测有效性;
通过在类内 函数实现成员属性和行为的读和写,通过函数检测写的有效性;
类中的属性和行为我们统一叫成员, 属性又叫 成员属性 或 成员变量; 行为叫成员函数 or 成员方法。
对象特性
对象的初始化和清理,C++中每个对象都有初始值的设置 和 销毁前清理数据的设置
构造函数和析构函数
构造函数:主要在创建对象时 为对象的成员属性赋值,系统自动调用且只调用一次;
析构函数:在对象销毁前系统自动调用,执行清理工作
析构函数和构造函数都是已经有的实现,如我们自己不提供,编译器会提供一个空实现
构造函数:
函数没有返回值 也不写void ;函数名与类名相同;函数可以有参数 可以发生函数重载;编译器在调用对象时自动调用构造函数且只调用一次。
析构函数:
函数没有返回值也不写void; 函数名与类名相同在名称前加 ~;函数不可以有参数 也不能发生函数重载, 编译器在对象销毁前自动调用析构函数 且只调用一次
class Person
{
public:
Person()
{
cout << "构造函数的调用" << endl;
}
~Person()
{
cout << "析构函数的调用" << endl;
}
};
构造函数的调用及分类:
按参数分: 有参构造 、 无参构造(默认构造)
按类型分: 普通构造 、 拷贝构造
调用: 括号法 显示法 隐式转换法
class Person
{
public:
Person ()
{
cout << "默认构造函数(无参构造)" << endl;
}
Person(int a)
{
cout << "有参构造函数的调用" << endl;
m_A =a;
}
Person(const Person &p)
{
m_A = p.m_A;
cout << "拷贝构造函数的调用" << endl;
}
~Person()
{
cout << "析构函数的调用" << endl;
}
int m_A;
};
int main()
{
Person p1;
Person p2(10);
Person p3(p2) ; // 括号法调用各构造函数
// 默认函数构造 不能加 括号;因为编译器会认为这是一个函数的声明
// 显示法调用
Person p4 = Person (10) ;
Person p5 = Person (p4);
// 数据类型 () 表示一个匿名对象, 如 Person(10); 匿名对象见名知意 就是无名字,
// 不能用拷贝函数来初始化匿名对象 如: Person(p1) 编译器会认为是: Person p1 ; 会认为是对象的声明
// 隐式转换法调用
Person p6 = 10;
Person p7 = p6; // 相当于 Person p7 = Person (p6);
return 0;
}
拷贝函数的调用时机
C++中调用拷贝构造函数通常有三种情况:
(1)使用一个已经创建完毕的对象来初始化一个对象(赋值 )
(2)值传递时给函数参数传值
(3)以值的方式返回局部对象
Person test ()
{
Person p;
return p; //以值的方式返回局部对象 时 调用拷贝构造函数
} // 拷贝构造函数本质是将值拷贝一份 赋值给新的对象或参数, 并不是把对象本身或参数本身传递过去
构造函数的调用规则
默认情况下: C++ 中一般给类添加至少四个函数
(1)默认构造函数(无参,函数体为空)
(2)默认析构函数(无参,函数体为空)
(3)默认拷贝构造函数, 对值进行简单的拷贝操作
(4)默认赋值运算符重载 operator= ,对属性进行值拷贝
调用规则如下:
如果用户自己定义了有参构造函数,那么编译器不会提供默认构造函数(无参构造),但是会提供拷贝构造函数。
如果用户自己定义了拷贝构造函数, 那么编译器不会提供默认构造函数和有参构造函数,需要自己定义。
深拷贝和浅拷贝
面试中常见的问题; 浅拷贝: 简单的赋值拷贝 ; 深拷贝: 在堆区重新开辟空间,进行拷贝赋值
析构函数的作用:用来释放堆区开辟的空间
class Person
{
public:
Person(int a, int b)
{
m_A = a;
m_B = new int (b); // 给值b在堆区开辟一块空间存放在m_B中
}
Person (const Person &p)
{
cout << "拷贝函数的调用" << endl;
m_A =p.m_A;
m_B = new int (p.m_B); //重新开辟一块空间给对象属性,防止浅拷贝带来的问题
}
~Person()
{
cout << "析构函数的调用" << endl;
if (m_B != NULL)
{
delete m_B ; //释放掉m_B存放的空间
m_B = NULL;
}
}
int m_A ;
int *m_B ;
};
int main()
{
Person P1(10);
Person P2(p1); //
return 0;
}
初始化列表:语法: 构造函数 () : 属性1(值1),属性2 (值2) { }
class Person
{
public:
Person(int a, int b) : m_A(a),m_B(b) { }
int m_A;
int m_B;
};
类中的成员可以是另一个类中的对象。称为对象成员
调用时:先调用对象成员的构造函数 在调用本类的构造函数;析构函数调用相反