【面向对象编程】

【面向对象编程】

基本概念

对象

属性(数据)
方法(操作)

继承

允许一个类从另一个类继承属性和方法->实现代码重用
eg 创建一个电动车类,继承自汽车类,并添加特有的属性,如电池容量,并仍然拥有汽车的特性,比如速度

多态

允许不同类的对象以相同的方式调用相同的方法
eg 汽车类和电动车类都可以有一个行驶方法

封装

限制外部访问 可以保护对象的数据不被随意修改

代码示例
#include<string>
#include"rclcpp/rclcpp.hpp"

class PersonNode : public rclcpp::Node//继承父类
{
private:
	std::string name_;
	int age_;

public:
	//构造函数
	PersonNode(const std::string &node_name,
	  const std::string &name,
	  const int &age): Node(node_name)//继承父类函数
	{
		this->name_=name;
		this->age_=age;
	};
	
	void eat(const std::string &food_name)
	{
		RCLCPP_INFO(this->get_logger(),"我是%s,今年%d岁,我现在正在吃%s",
			name_.c_str(),age_,food_name.c_str());
	};
};

int main(int argc,char** argv){
	rclcpp::init(argc,argv);
	//构造函数
	auto node=std::make_shared<PersonNode>("cpp_node","麦麦",18);
	node->eat("vw50");
	rclcpp::spin(node);
	rclcpp::shutdown();
	return 0;
}

访问权限

public:公共权限,允许内外部直接访问
private:私有权限,只允许内部访问
protected:保护权限,跟私有类似,但在继承中与私有不同

初始化
【定义】
pubilc:
	Student(int ID, std::string Name): id(ID), name(Name) {}
【调用】
Student s1(114514, “pikachu”);
析构函数

在每次删除所创建的对象时执行
不编写析构函数,编译器自动会生成一个默认的析构函数

~Student();
复制构造函数

使用同一类中之前创建的对象来初始化新创建的对象

Student(const Student &obj){};
this指针

指向对象地址本身的指针

class Student{  
    public: 
		void changeName(std::string name){
            this->name=name;
        }
}
引用&:和指针类似

直接指向内存中某个具体的对象

int main(){
    Student stu1(114514,"pikachu");
    Student &stu2=stu1;
    stu1.display();
    stu2.display();
    stu2.changeName("asd");
    stu1.display();
}

改变stu2就是改变stu1

!!!在编写函数参数时,如果需要使用一个类来作为参数,建议使用引用

优点
(1)不使用引用,在传入时对象会被复制一份
如果需要操作被传入的对象,可能会出现问题,比如源对象没被修改
(2)避免复制,节约空间

继承:公有继承,保护继承,私有继承

class Derive:public Base{}     //创建一个Derive类,公有继承Base类
class Derive:Base{}	       //默认私有继承

公有继承
基类和派生类相同属性

保护继承
基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问

私有继承
即所有基类成员均变成派生类的私有成员

运算符重载:operator

class list{
public:
    list(int a,int b):a(a),b(b){}
    list operator+(const list &l){
        return list(a+l.a,b+l.b);//只需要一个l.a
    };
    list operator-(const list &l){
        return list(a-l.a,b-l.b);
    };
    void show(){
        std::cout<<"a="<<a<<" b="<<b<<std::endl;
    }
private:
    int a;
    int b;
};
int main(){
    list l1(1,2);
    list l2(4,5);
    list l3=l1+l2;//1+4=5 2+5=7
    list l4=l1-l2;
}

image

内存管理

int *p = new int(114);	//申请一个int类型的内存,并赋值
int *array = new int[100000]; // 申请十万个 int 类型的内存 
delete [] array; // 释放内存

智能指针

std::shared_ptr p1(new int(1)); 	//p1 是一个指向 int 类型的智能指针
std::cout<<*p1<<“\n”;		//使用方式跟普通指针没什么区别

共享指针shared_ptr:可以有多个 shared_ptr 指向一个对象,当最后一个 shared_ptr 销毁时,对象也会被销毁
独占指针unique_ptr:独立管理一个对象的生命周期,只有一个 unique_ptr 指向一个对象,当 unique_ptr 销毁时,对象也会被销毁
弱指针weak_ptr:弱引用,通常与 shared_ptr 搭配,不会增加对象的引用数,当最后一个shared_ptr 销毁时,对象也会被销毁

共享指针

【创建】

auto cat_p = make_shared<Cat>("cat333");
cat_p->speak();
shared_ptr<Cat> cat1=cat;	//复制,然后计数器加一
cat1=nullptr;			//删除指针,然后计数器减一

Copy则计数器+1,销毁则计数器-1
使用use_count()查看计数器

独占指针

独占指针需要使用std::move()来移交内存拥有权,不能被复制,只能被移动
在形参使用引用

// 从原始指针创建,注意需要销毁原始指针
auto cat_p1=new Cat("cat111");  // 创建原始指针
unique_ptr<Cat> cat_p2(cat_p1); // 创建独占指针
cat_p1=nullptr;                 // 原始指针置空
delete cat_p1;                  // 释放原始指针
cat_p2->speak();
// 直接创建
unique_ptr<Cat> cat_p1(new Cat(“cat222"));
cat_p1->speak();
// 使用函数创建(推荐)
auto cat_p = make_unique<Cat>("cat333");
cat_p->speak();
弱指针

(1)没有所有权,不能调用-> 和 解引用*
(2)解决循环依赖问题:A对象需要存储其他A对象的信息
(3)不能单独存在

constexpr 关键字

(1)编译期就能得到计算结果->在用来提高性能和检查错误时会有帮助
(2)可以使用 constexpr 代替 #define 定义常量
(3)constexpr也可以用来申明函数,支持递归
image
image

匿名函数:Lambda 表达式

[捕获列表] (参数列表) -> 返回类型 { 函数体 ;};
#include<iostream>
#include<algorithm>
int main(){
    auto add=[](int a,int b) -> int {return a+b;};
    int sum=add(200,50);
    auto print_sum=[sum]()->void{std::cout<<sum<<std::endl;};
    print_sum();
    return 0;
}

函数包装器std::function

存储任意可调用对象(函数、函数指针、Lambda表达式)并提供统一调用接口

std::function<void(const std::string &)>

std::bind:将一个成员函数变成一个std::function的对象

正常调用成员函数:file_save.save_with_member_fun
->将FileSave::save_with_member_fun与对象file_save绑定在一起

std::placeholders::_1 占位符预留1个位置传递函数参数

示例

#include<iostream>
#include<functional>

void save_with_free_fun(const std::string &file_name)
{
	std::cout<<"调用自由函数,保存"<<file_name<<std::endl;
}

class FileSave
{
public:
	void save_with_member_fun(const std::string &file_name)
	{
		std::cout<<"调用成员方法,保存"<<file_name<<std::endl;
	};
};

int main()
{
	FileSave file_save;
	auto save_with_lambda_fun=[](const std::string &file_name) -> void
	{
	 	std::cout<<"调用Lambda函数,保存"<<file_name<<std::endl;
	};
	//将自由函数放入function对象
	std::function<void(const std::string &)> save1=save_with_free_fun;
	//将Lambda函数放入function对象
	std::function<void(const std::string &)> save2=save_with_lambda_fun;
	//将成员方法放入function对象
	//std::function<void(const std::string &)> save3=
		std::bind(&FileSave::save_with_member_fun,&file_save,
		std::placeholders::_1);
	//调用形式统一
	save1("file.txt");
	save2("file.txt");
	save3("file.txt");
	return 0;
}

多线程与回调函数

std::this_thread 当前线程

示例

#include<iostream>
#include<chrono>//时间相关
#include<thread>//线程相关
#include<functional>//函数包装器

class Download
{
public:
	//传入两个参数:std::function->函数
	void download(const std::string &host,const std::string &path,
	 const std::function<void(const std::string &,
	 const std::string &)> &callback)
	 //callback:回调函数:请求成功后调用,传递请求结果
	{
		std::cout<<"线程ID:"<<std::this_thread::get_id()<<std::endl;
		httplib::Client client(host);
		auto response=client.Get(path);
		if(response && response->status == 200)//执行回调函数
		{
			callback(path,response->body);
		}
	}
	
	//包装download函数->添加多线程
	void sart_download(const std::string &host,const std::string &path,
	  const std::function<void(const std::string &,const std::string &)>
	    &callback)
	{                                                 //当前类的指针
		auto download_fun = std::bind(&Download::download,this,
		  std::palceholders::_1,std::palceholders::_2,std::palceholders::_3);
		//创建thread对象
		std::thread download_thread(download_fun,host,path,callback);
		//将线程与当前进程分离->线程在后台运行
		download_thread.detach();
	}
}

int main()
{
	Download download;
	auto download_finish_callback = [](const std::string &path,
	  const std::string &result) -> void
	{
		std::cout<<"下载完成"...
	};
	
	//创建三个线程
	download.start_download("...","...",download_finish_callback);
	download.start_download("...","...",download_finish_callback);
	download.start_download("...","...",download_finish_callback);
	
	//延迟当前线程
	std::this_thread::sleep_for(std::chrono::milliseconds(1000*10));
	return 0;
}
posted @ 2024-11-07 19:45  White_ink  阅读(28)  评论(0)    收藏  举报