1 类
何为类:具有相同性质的对象,可抽象为类,如长方体的length、width、height 这些属于长方体的属性封装为类。
cpp
class cuboid{
public:
int length;
int width;
int height;
void volume(){
std::count<<length*width*height<<endl;
}
};
this指针
this是隐含在非静态成员函数内部 的指针,指向调用该成员函数的对象。它是一个常量指针 (
ClassName * const this),不能改变this本身指向的对象,但可以通过this修改对象的成员(除非成员函数是const的)。
cpp
class MyClass {
int value;
public:
//在 非 const 成员函数 中,this 的类型是 ClassName * const,
//可以通过 this 修改对象的成员。
MyClass& setValue(int value) {
this->value = value; // 区分形参与成员
return *this; // 返回对象本身,支持链式调用
}
//在 const 成员函数 中,this 的类型是 const ClassName * const,
//不能通过 this 修改非 mutable 成员。
void print() const {
// this->value = 10; // 错误:const 成员函数中 this 指向 const 对象
cout << this->value; // 可以读取
}
};
用途
当形参和成员变量同名时可用this区分
在类的非静态成员函数中返回对象本身,可使用return *this
1.1 类的访问权限
| 权限 | 类内访问 | 派生类内访问 | 类外(对象)访问 |
|---|---|---|---|
| public(公共) | ✔ | ✔ | ✔ |
| protected(受保护) | ✔ | ✔ | ✘ |
| private(私有) | ✔ | ✘ | ✘ |
类内:本类定义的成员函数
派生类:子类定义的成员函数
类外对象:实例化的对象使用指针或者通过 成员访问运算符**.** 调用
1.2 构造函数和析构函数
对象的初始化和清理是编译器强制要求的,不提供构造和析构,编译器会提供空实现
构造函数:类名(){} 析构函数:~类名(){}
cuboid(); ~cuboid();
- 没有返回值
- 构造函数可以有参数可重载,析构函数没参数
- 自动调用只会调用一次
1.2.1 构造函数
- 创建新对象时进行初始化对属性赋值,编译器自动调用
cpp
class cuboid{
public:
int length;
int width;
int height;
//构造函数
cuboid(int a,int b,int c){
length=a;
width=b;
height=c;
}
};
//调用
cuboid(1,2,3);
1.2.2 调用规则
|-----------|-----------|----------------------------|
| 调用规则 | 调用类型· | |
| 默认构造、析构函数 | 空函数 | 对类内变量不做初始化 |
| 默认拷贝构造函数 | 属性值拷贝 | 属性值赋值(指针只复制其地址-->指向同一块地方) |
| 定义有参数构造函数 | 不提供无参构造函数 | 声明构造函数后,不生成无参构造函数 |
| 定义拷贝构造函数 | 不提供无参构造函数 | 同上,可自定义有参构造 |
1.2.3 调用方式
- 括号法
- person p1;---默认构造函数调用
- 调用默认构造不用加()
- person p2(10);---有参构造函数调用
- person p3(p2);---拷贝构造函数调用
- person p1;---默认构造函数调用
- 显示法
- person p1;
- person p2 = person(10);---有参构造
- person p3 = person(p2);---拷贝构造
- 隐式转换法
- person p1=10; 等价--> person p1=person(10);
- person p2=p1; 等价--> person p2=person(p1);
1.2.4 深拷贝与浅拷贝
- 浅拷贝单纯属性赋值
- 在堆区中拷贝出一份新内存
- 如果属性有在堆区开辟的,需深拷贝。
1.2.5 初始化列表
cpp
构造函数():属性1(值1),属性2(值2)...{}
MinimalPublisher() : Node("minimal_publisher"), count_(0){
函数体
}
1.2.6 析构函数
对象销毁前系统进行自动清理
1.3 继承
class 子类 :继承方式 父类
cppclass son : public 作用域::father子类也称派生类 父类---基类
父类所有非静态成员属性都会被继承;但私有权限在子类变不可访问;继承多少类就会多占多少内存空间

1.3.1 继承方式
|----------|----------------------------------|
| 公共继承 | 与父类权限相同private不可访问 |
| 保护继承 | 除了private其他到子类变protected |
| 私有继承 | 子类全为private,并且在父类为private的子类不可访问 |
- 继承构造析构顺序
- 先构造父类再子类,析构相反
2 模板
建立一个通用函数,返回值类型和形参类型可不具体制定,用一个虚拟的类型来代表。
2.2 函数模板
如下实现int || float 类型变量的交换:
cpp
#include <iostream>
using namespace std;
void swapint(int* a, int* b)//交换int
{
int p = *a;
*a = *b;
*b = p;
}
void showint(int a, int b)//输出
{
cout << "a=" << a << "," << "b=" << b << endl;
}
void swapfloat(float* a, float* b)
{
float p = *a;
*a = *b;
*b = p;
}
void showfloat(float a, float b)
{
cout << "a=" << a << "," << "b=" << b << endl;
}
int main()
{
int a1 = 3, b1 = 12;
swapint(&a1, &b1);
showint(a1, b1);
float a2 = 12.3, b2 = 45.1;
swapfloat(&a2, &b2);
showfloat(a2, b2);
return 0;
}
函数内部实现基本重复,能否只写一种函数就实现两种不同类型变量的交换呢
普通函数将变量作为参数,而模板能将变量类型也参数化~
模板格式
template <typename 形参名, typename 形参名...> //模板头(模板声明)
cpp返回值类型typename 函数名funtion()(参数列表) //函数定义{
函数体;
}
经过模板简化后的不同类型变量相加
cpp
#include <iostream>
using namespace std;
template<typename T>//模板头,template关键字告诉编译器开始泛型编程
T add(T t1, T t2)//类型参数化为T
{
return t1 + t2;
}
int main()
{
cout << add(12, 34) << endl; //自动类型推导,必须推导出一致的数据类型T,才可以使用
cout << add(12.2,45.6) << endl;
return 0;
}
模板指定类型声明(显式声明):
也可不声明直接使用显式声明
cpp
声明格式:template 函数返回值类型 函数名<实例化的类型>(参数列表);
template int add<int>(int t1, int t2);//显示实例化为int类型
#include <iostream>
using namespace std;
template<typename T>
T add(T t1, T t2)
{
return t1 + t2;
}
template int add<int>(int t1, int t2);//显示实例化为int类型
int main()
{
cout << add<int>(12, 'A') << endl;//函数模板调用:A-65
cout << add(1.4, 5.7) << endl;//隐式实例化:自动实参推演
cout << add<int>(23.4, 44.2) << endl;//显示声明可省,结果为67
return 0;
}
普通函数与函数模板的调用规则
- 如果函数模板和普通函数都可以实现,优先调用普通函数
- 可以通过空模板参数列表来强制调用函数模板----myPrint<>(a, b);
- 函数模板也可以发生重载
- 如果函数模板可以产生更好的匹配,优先调用函数模板
2.2 类模板
- 建立一个通用类,类中的成员数据类型可以不具体制定,用一个虚拟的类型来代表。
- 类模板在模板参数列表中可以有默认参数----template<class AgeType = int>
2.2.1 模板格式
cpp
template<typename 形参名,typename 形参名...>
class 类名
{
.........
}
ttemplate<typename T1, typename T2>
class B
{
public:
T1 a;
T2 b;
T1 func(T1 a, T2& b);
};
B <int, string> b; //创建模板类B的一个对象
2.2.2 对象指针创建(左右两边类型要一 一对应):
cpp
Point<float, float> *p1 = new Point<float, float>(10.6, 109.3);
Point<char*, char*> *p = new Point<char*, char*>("东京180度", "北纬210度");
2.2.3 类模板对象做函数参数
指定传入的类型
cpp
// 指定传入的类型 ------ 直接写出对象的数据类型
void printPair1(const Pair<int>& p) { // 显式指定为 int 类型
p.show();
}
参数模板化
cpp
// 参数模板化 ------ 将 Pair 中的 T 变为模板参数
template<typename T>
void printPair2(const Pair<T>& p) {
p.show();
}
整个类模板化
cpp
//整个类模板化 ------ 将 Pair<T> 整体视为一个类型,用模板参数替代
template<typename T>
void printPair3(const T& obj) {
obj.show(); // 要求 C 类型必须有 show() 方法
}