C++面向对象--类、模板

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 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. 在堆区中拷贝出一份新内存
  3. 如果属性有在堆区开辟的,需深拷贝。

1.2.5 初始化列表

cpp 复制代码
构造函数():属性1(值1),属性2(值2)...{}
MinimalPublisher() : Node("minimal_publisher"), count_(0){
    函数体
}

1.2.6 析构函数

对象销毁前系统进行自动清理

1.3 继承

class 子类 :继承方式 父类

cpp 复制代码
class 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;
}

普通函数与函数模板的调用规则

    1. 如果函数模板和普通函数都可以实现,优先调用普通函数
    1. 可以通过空模板参数列表来强制调用函数模板----myPrint<>(a, b);
    1. 函数模板也可以发生重载
    1. 如果函数模板可以产生更好的匹配,优先调用函数模板

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() 方法
}
相关推荐
William_wL_2 小时前
【C++】list的使用
c++
Elnaij2 小时前
从C++开始的编程生活(25)——C++11标准Ⅱ
开发语言·c++
cjforever142 小时前
各STL容器的模拟实现
开发语言·数据结构·c++
郝学胜-神的一滴2 小时前
Linux高性能网络编程基石:epoll核心与文件描述符限制全解
linux·服务器·网络·c++·后端
房开民10 小时前
c++总结
java·开发语言·c++
好大哥呀10 小时前
C++ 多态
java·jvm·c++
墨韵流芳12 小时前
CCF-CSP第41次认证第三题——进程通信
c++·人工智能·算法·机器学习·csp·ccf
hz_zhangrl12 小时前
CCF-GESP 等级考试 2026年3月认证C++五级真题解析
c++·青少年编程·程序设计·gesp·c++五级·gesp2026年3月·gesp c++五级
Σίσυφος190012 小时前
C++ 多肽经典面试题
开发语言·c++·面试