一. 面向对象基础
1.类与对象的概念
类:类是对同一类对象的抽象总结,是一个概念。 一个类最主要包括属性和行为
对象:按照类的规定创建的实体。
2.实例化对象
类是一个抽象的概念,所以需要我们按照概念来创建对应的对象。在C++中有两种类型的对象:分别是栈内存对象,堆内存对象。
- 栈内存对象
在生命周期结束(所在的花括号执行完)后,自动被销毁。
栈内存对象使用 . 调用成员。
- 堆内存对象
需要使用new关键字创建,使用delete关键字销毁,如果不销毁,则会持续存在,容易导致 内存泄漏的问题,内存泄漏最终可能会导致程序卡顿,甚至卡死。
堆内存对象通常使用指针来保存堆内存对象的地址。
堆内存对象使用 -> 调用成员,在Qt Creator下,直接打.会转换成 ->
4.封装
封装就是根据业务的需求将类的一些属性和细节隐藏起来,并重新公开给外部一些开放的调用接口。当然它的封装写法也不唯一,在实际的过程中结合业务需求而定。通常先对属性私有化,使属性隐藏,然后根据当前属性的需求,通过getter函数和setter函数对类外分别公开读和写的功能。如下代码:
#include <iostream>
using namespace std;
class MobilePhone
{
private: // 私有权限:只有类内部可访问
string brand; // 可读可写
string model; // 只写
int weight = 188; // 初始值
public: // 公开接口
string get_brand() // getter:读属性
{
return brand;
}
void set_brand(string b) // setter:写属性
{
brand = b;
}
void set_model(string m) // setter
{
model = m;
}
int get_weight() // getter
{
return weight;
}
};
int main()
{
MobilePhone mp1;
mp1.set_brand("小米");
mp1.set_model("13 Pro");
cout << mp1.get_brand() << " " << mp1.get_weight() << endl;
MobilePhone* mp2 = new MobilePhone;
mp2->set_brand("红米");
mp2->set_model("K60 Pro");
cout << mp2->get_brand() << " " << mp2->get_weight() << endl;
delete mp2;
return 0;
}
二 . 构造函数
构造函数类内一种特殊的函数,用来创建一个对象。如果一个类中,程序员不手动编写构造函数,编译器会为这个类自动添加一个无参构造函数,且此函数的函数体为空;如果程序员手写了任意一个构造函数,编译器就不再自动添加构造函数了。构造函数要求函数名必须与类名完全一致,且构造函数无需写返回值。
- 2.用法
- 可以给构造函数增加参数,使用参数给属性赋予初始值,使对象的创建更灵活。
- 构造函数也支持函数重载,遵守之前函数重载的规则。
- 构造函数也支持之前的参数默认值设定。
三 . 构造初始化列表
1. 构造初始化列表是一种简便的写法,可以用于给属性赋予初始值。
#include <iostream>
using namespace std;
class MobilePhone
{
private:
string brand;
string model;
int weight;
public:
MobilePhone(string b = "8848",
string m="钛金手机",
int w = 199):brand(b),model(m),weight(w)
{}
void show() // 展示所有属性值
{
cout << brand << " " << model << " "
<< weight << endl;
}
};
int main()
{
MobilePhone mp1("小米","13Pro",190);
mp1.show();
return 0;
}
四 . 析构函数
1.析构函数是与构造函数对立的函数
构造函数 |
析构函数 |
手动调用 |
在对象被销毁时自动调用 |
通常用于在对象创建时初始化 |
通常用于在对象销毁时回收资源 |
可以被重载 |
不可以重载,因为没有参数 |
函数名是类名 |
函数名是~类名 |
五 .作用域限定符 ::
1.内类声明,内外定义
对于类中的成员也可以声明定义分离,如果声明定义分离,通常在类内声明,在类外定义,类外的定义需要结合作用域限定符使用。
#include <iostream>
using namespace std;
class Test
{
private:
string str = "随便";
public:
// 类内声明
Test(); // 无参构造
string get_str(); // getter
};
// 类外定义
string Test::get_str()
{
return str; // 也属于类内
}
Test::Test()
{
cout << "构造函数" << endl;
}
int main()
{
Test t;
cout << t.get_str() << endl;
return 0;
}
六.this指针
1. 概念
this指针是一个特殊的指针,保存的是当前类的对象首地址。
this所在的函数是哪个对象的,this指向的就是这个对象。
2.原理
在类内调用此类的成员,虽然不用手写this指针,但是编译器都会使用this指针来调用成员,因为成员只能由对象来调用,而this指针指向的就是当前类的对象。
#include <iostream>
using namespace std;
class Student
{
private:
string name;
public:
Student(string s)
{
this->name = s;
}
string get_name()
{
return this->name;
}
void show()
{
cout << this->get_name() << endl;
}
};
int main()
{
Student s("张三");
s.show(); // 张三
return 0;
}
3.利用this指针的原理,其应用有:
- 区分重名的成员变量与局部变量--------当成员变量与局部变量重名时,可以使用this指针调用成员变量。
- 链式调用------如果一个函数的返回值是当前类的引用,那么通常此函数需要返回一个*this,并且此函数支持链式调用。
- 多态传参
七. static关键字
1.static关键字在类内有以下几种用法:
- 静态局部变量------使用static关键字修饰局部变量就是静态局部变量。
- 静态成员变量-----------成员变量使用static修饰就是静态成员变量,静态成员变量有以下特点: 1. 此类的所有对象共用此变
2.非const的静态成员变量通常需要类内声明,类外初始化
3. 静态成员变量可以直接使用类名::来调用,更推荐使用此方式
4.静态成员变量在程序运行时创建,在程序结束时销毁
- 静态成员函数--------------成员函数使用static修饰就是静态成员函数,静态成员函数的特点有:
1.静态成员函数不能访问此类中非静态成员,因为没有this指针
2.静态成员函数只能调用本类中静态的成员
3.非静态成员函数可以调用静态成员
4.除了可以使用当前类对象调用静态成员函数外,也可以直接使用类名::调用,
5.如果静态成员函数声明与定义分离,只需要在声明处使用static修饰
八.const关键字
1. 在C++中,虽然认为const表示常量的意思,但是严格地讲,const并不是常量。因为C++中const只能在程序的运行期间只读,即在编译期可以改变数值。
常成员函数:const修饰的成员函数,表示常成员函数,这种函数的特点是:
1.可以调用本类中非const的成员变量,但是不能修改其数值
2.不能调用非const的成员函数
建议成员函数只要不修改成员变量值就写为常成员函数,例如getter
常量对象:const修饰对象,表示该对象为常量对象,其特点有:
1.常量对象的任何属性值不能被修改
2.常量对象不能调用任何非const的成员函数
const修饰对象时,const关键字可以写在类名前面,也可以类名后面。
常成员变量:使用const修饰成员变量,表示该成员变量为常成员变量,其特点有:
1.程序运行时,常成员变量的值不可变
2.不能在函数体中赋值,只能通过直接赋值或构造初始化列表赋值
修饰局部变量:类似于之前给引用参数增加const修饰,函数的局部变量都可以使用const修饰,表示常量。
九.运算符重载
1. 友元:友元是一种定义在类外部的普通函数,但他需要在类内进行说明,为了和该类的成员函数加以区别,在说明时前面加以关键字friend。
友元主要分为以下几种使用情况:
- 友元函数
- 友元类
- 友元成员函数
友元函数:友元函数是一种类外的函数,但是需要在类内结合friend关键字进行说明(非声明),需要注意以下几点:
- 因为友元函数不是类内的函数,因此没有this指针,因此需要给友元函数增加一个传递对象的参数位,用此对象来调用类中的成员。
- 友元函数不属于类,因此不受类中权限修饰符的影响,即友元函数的说明可以放在类中的任意位置。
- 一个友元函数可以访问多个类的成员,只需要在多个类中分别说明。
#include <iostream>
using namespace std;
class Test
{
private:
int a = 1;
// 友元函数的说明,放在类中的任意位置都可以
friend void test_friend(Test& t);
};
// 友元函数在类外
void test_friend(Test& t)
{
t.a++;
cout << t.a << endl;
}
// 不是友元函数
void test(Test& t)
{
// t.a++; 错误
// cout << t.a << endl; 错误
}
int main()
{
Test t;
test_friend(t); // 2
return 0;
}
友元类:当一个类B成为了另一个类A的“朋友”时,类A的所有成员就可以被类B访问,此时类B是类A的友元类。需要注意的是:
- 友元关系是单向的,不具有交换性。
- 友元关系不具有传递性。
- 友元关系不能被继承。
友元成员函数:可以使类B中的某一个成员函数成为类A的友元成员函数,这样类B中只有这个成员函数可以访问类A的所有成员。
#include <iostream>
using namespace std;
// 第三步
class A;
// 第二步
class B
{
public:
void func(A& a); // 先只声明
};
// 第一步
class A
{
private:
int i = 1;
// 说明友元成员函数
friend void B::func(A& a);
};
// 第四步,补齐友元函数的定义
void B::func(A &a)
{
a.i++;
cout << a.i << endl;
}
int main()
{
A a;
B b;
b.func(a); // 2
return 0;
}
运算符重载:
1. 概念:函数可以重载,运算符也是一种特殊的函数,因此运算符也可以重载。
可以被重载的运算符:
算术运算符:+、-、*、/、%、++、--
位操作运算符:&、|、~、^(位异或)、<<(左移)、>>(右移)
逻辑运算符:!、&&、||
比较运算符:<、>、>=、<=、==、!=
赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=
其他运算符:[]、()、->、,、new、delete、new[]、delete[]
不被重载的运算符:
成员运算符 .、指针运算符 *、三目运算符 ? :、sizeof、作用域 ::
友元函数运算符重载:
可以使用友元函数进行运算符重载。
class Integer
{
private:
int value;
public:
Integer(int value):value(value){}
int get_value() const
{
return value;
}
// 友元函数的说明
friend Integer operator +(const Integer& i1,
const Integer& i2); // 双目
friend Integer operator ++(Integer& i); // 单目,前置
friend Integer operator ++(Integer& i,int); // 单目,后置
};
Integer operator +(const Integer& i1,
const Integer& i2)
{
return i1.value+i2.value;
}
Integer operator ++(Integer& i)
{
return ++i.value;
}
Integer operator ++(Integer& i,int)
{
return i.value++;
}
成员函数运算符重载:
也可以使用成员函数进行运算符重载,成员函数的运算符函数对应的输入参数比同样使用友元函数实现的友元函数的参数少一个。
class Integer
{
private:
int value;
public:
Integer(int value):value(value){}
int get_value() const
{
return value;
}
// 成员函数运算符重载
Integer operator +(const Integer& i);
Integer operator ++(); // 前置
Integer operator ++(int); // 后置
};
Integer Integer::operator +(const Integer& i)
{
// this表示运算数1
return this->value+i.value;
}
Integer Integer::operator ++()
{
return ++this->value;
}
Integer Integer::operator ++(int)
{
return this->value++;
}
赋值运算符重载:
赋值运算符重载函数只支持成员函数运算符重载,不支持友元函数运算符重载的方式。
相关部分代码
// 编译器自动添加赋值运算符重载函数
Teacher& operator =(const Teacher& right)
{
this->subject = right.subject;
cout << "赋值运算符:" << subject << endl;
return *this;
}
- 当前类的成员变量出现指针
- 屏蔽赋值运算符的使用(权限为private)
operator string() // 格式比较特殊
{
return subject;
}
十.字符串类 std::string
std::string是一种特殊容器的类型,用于操作字符序列。
empty ---空
swap-----交换
append---向后追加字符串
insert-------插入
replace----替换
erase----删除