实现自定义类型比较的三种改写方法 -- 以set<Point>为例

前置

模板 – 打印

CppBaseDay21

重载 <<

os 是泛化的 std::ostream

  • operator<< 函数中,osstd::ostream 的引用,这意味着它可以代表任何具体的输出流,例如 std::coutstd::ofstream(文件输出流)、std::ostringstream(字符串输出流)等。
  • 当你向 operator<< 传递 std::cout 时,os 实际上就是 std::cout 的引用;但你也可以将其他流传递给 os,例如文件流对象或字符串流对象。

cout 是特定的 std::ostream 实例

  • std::cout 是一个具体的 std::ostream 实例,它与标准输出(通常是终端/控制台)相关联。你可以直接用 std::cout 来向屏幕打印消息。
  • cout 不能替代 os,因为 os 可以是任何输出流,而 cout 仅指向标准输出。

使用namespace std { }的原因

当我们对标准库模板进行特化时,必须将特化放入 std 命名空间,因为这些模板是在 std 命名空间中定义的。如果不放在 std 命名空间中,编译器将无法将其视为对标准模板的特化,而是会当成一个独立的新模板。


第一种方式 – 模板的特化

类模板特化 template<> struct less<Point>

//类模板定义
template <class/typename T, ...>
class 类名{
//类定义......
};
//chatgpt给出的示例:
namespace std {
    template <class T>	//less<Point> 是对模板 less<T> 的特化,Point 是 T 的具体类型
    struct less {
       ……
    };
}

//代码中的写法 
template <>
struct less<Point>//模板的特化
{
	……
}
  • template<>:这是模板特化的语法,表示我们将为模板类 std::less 提供一个特化版本,用于处理 Point 类型。

  • struct less<Point>:我们在 std::less 模板中为 Point 类型提供特化,即定义一个新的规则用于比较 Point 对象。。

这个特化会覆盖默认的 std::less 行为–在标准库中,std::less 是一个类模板,用于定义对象之间的比较操作(通常是 < 运算符)。它的默认实现会使用 < 运算符来比较对象。

struct less<Point> 是对 std::less 这个模板类的特化,这里的 Point 具体化了模板参数 T

less 是类名,T 是一个类型参数。这个模板类可以用来创建不同类型的比较器,例如 less<int>less<double> 等。

  • operator():这是重载的函数调用运算符,定义了 less<Point> 如何比较两个 Point 对象。在这个例子中,我们首先比较 x 坐标,如果 x 坐标相等,则比较 y 坐标。

为什么要末尾要加const–成为const成员函数被调用

const/非const对象 以及 const/非const函数

在 const 对象上调用成员函数

  • 只能调用 const 成员函数。
  • 不能调用非常量成员函数。

在非常量对象上调用成员函数

  • 可以调用 const 和非 const 成员函数(优先,没有再调用const版本)。
chatgpt例子
class MyClass {
public:
    int value;

    // 非 const 成员函数
    void setValue(int v) {
        value = v; // 修改值
    }

    // const 成员函数
    int getValue() const {
        return value; // 只读
    }
};

int main() {
    MyClass obj; // 非 const 对象
    obj.setValue(5); // 可以调用
    int val = obj.getValue(); // 可以调用

    const MyClass constObj; // const 对象
    // constObj.setValue(10); // 错误,不能调用非 const 成员函数
    int constVal = constObj.getValue(); // 可以调用 const 成员函数

    return 0;
}
set源码中的成员函数operator()

看看吧。。。主要看图,格式就是这样要求的。。。

STL 容器(如 std::setstd::map)通常会使用传递的比较函数来比较元素。为了保证这些比较函数能够在使用时不改变容器中元素的状态,STL 要求这些函数必须是 可调用的(invocable)并且应该是 const 的。

以下是个人猜想。。。

set底层是const修饰的,因此set的对象只能调用const 成员函数

所以bool operator()(const Point &lhs,const Point &rhs)后面要加 const

//error
bool operator()(const Point &lhs,const Point &rhs) {……}
bool operator()(const Point &lhs,const Point &rhs) const {……}

在这里插入图片描述

//默认的模板
#if 0
namespace std
{
template <class T>
struct less
{
    bool operator()(const T &lhs, const T &rhs) const
    {
        return lhs < rhs;
    }
};
}//end of namespace std
#endif

形式

template <>
struct less<Point>//模板的特化
{
	……
}

代码1

在这里插入图片描述

#include <math.h>
#include <iostream>
#include <set>

using std::cout;
using std::endl;
using std::set;

//模板 -- 打印
template <typename Container>    //typename - class 
void display(const Container & con){
    for(auto & elem : con){
        cout << elem << " ";
    }
    cout << endl;
}

class Point
{
public:
    Point(int ix = 0, int iy = 0)
    : _ix(ix)
    , _iy(iy)
    {
    }

    //计算点到原点的距离
    float getDistance() const
    {
        return hypot(_ix, _iy);
    }

    int getX() const
    {
        return _ix;
    }

    int getY() const
    {
        return _iy;
    }

    ~Point()
    {
    }

    friend std::ostream & operator<<(std::ostream & os,const Point & rhs);   //Point

private:
    int _ix;
    int _iy;
};

//由于是自定义模板,需要重载 <<
//同时由于需要访问Point类的私有成员,因此在Point类中需要把该函数声明为友元
std::ostream & operator<<(std::ostream & os,const Point & rhs){
    os << "(" << rhs._ix << "," << rhs._iy << ")";
    return os;
}


//第一种 -- 模板的特化
namespace std
{
template <>
struct less<Point>  //less是类名,T是一个类型参数。例如 less<int>、less<double> 等。
{
    //比较2个Point类对象
    bool operator()(const Point &lhs,const Point &rhs) const
    {   
        cout << "template<> struct less" << endl;
        // x 和 y均采用升序的方式比较大小
        if(lhs.getX() < rhs.getX())
        {
            return true;
        }else if(lhs.getX() == rhs.getX()){
            if(lhs.getY() < rhs.getY()){
                return true;
            }else{
                return false;
            }
        }
        else    //lhs.getX() > rhs.getX()
        {
            return false;
        }
    } 
};
}   //end of namespace std


//第二种 -- 运算符重载


//第三种 -- 函数对象



void test0(){
    set<Point> number = {
        Point(1, 2),
        Point(-1, 2),
        Point(1, 4),
        Point(1, 2),
        Point(1, -2),
        Point(3, 2),
    };

    display(number);
}

int main()
{
    test0();       
    return 0;
}  

第二种方式 – 函数对象

形式

struct ComparePoint
{
	……
}

代码2

在这里插入图片描述

#include <math.h>
#include <iostream>
#include <set>

using std::cout;
using std::endl;
using std::set;

//模板 -- 打印
template <typename Container>    //typename - class 
void display(const Container & con){
    for(auto & elem : con){
        cout << elem << " ";
    }
    cout << endl;
}

class Point
{
public:
    Point(int ix = 0, int iy = 0)
    : _ix(ix)
    , _iy(iy)
    {
    }

    //计算点到原点的距离
    float getDistance() const
    {
        return hypot(_ix, _iy);
    }

    int getX() const
    {
        return _ix;
    }

    int getY() const
    {
        return _iy;
    }

    ~Point()
    {
    }

    friend std::ostream & operator<<(std::ostream & os,const Point & rhs);   //Point
    
    //friend struct ComparePoint;	//好像没将函数对象作为友元,代码运行也可以成功。。。
    								//因为使用了getX() 之类的函数,可以直接访问私有成员

private:
    int _ix;
    int _iy;
};

//由于是自定义模板,需要重载 <<
//同时由于需要访问Point类的私有成员,因此在Point类中需要把该函数声明为友元
std::ostream & operator<<(std::ostream & os,const Point & rhs){
    os << "(" << rhs._ix << "," << rhs._iy << ")";
    return os;
}

//第一种 -- 模板的特化

//第二种 -- 函数对象
struct ComparePoint
{
    //比较2个Point类对象
    bool operator()(const Point &lhs,const Point &rhs) const
    {   
        cout << "struct ComparePoint" << endl;
        // x 和 y均采用升序的方式比较大小
        if(lhs.getX() < rhs.getX())
        {
            return true;
        }else if(lhs.getX() == rhs.getX()){
            if(lhs.getY() < rhs.getY()){
                return true;
            }else{
                return false;
            }
        }
        else    //lhs.getX() > rhs.getX()
        {
            return false;
        }
    } 
};

//第三种 -- 运算符重载



void test0(){
    set<Point,ComparePoint> number = {
        Point(1, 2),
        Point(-1, 2),
        Point(1, 4),
        Point(1, 2),
        Point(1, -2),
        Point(3, 2),
    };

    display(number);
}

int main()
{
    test0();       
    return 0;
}  

第三种方式 – 运算符重载

形式

bool operator<(const Point & lhs,const Point & rhs)
{
	……
}

代码

在这里插入图片描述

#include <math.h>
#include <iostream>
#include <set>

using std::cout;
using std::endl;
using std::set;

//模板 -- 打印
template <typename Container>    //typename - class 
void display(const Container & con){
    for(auto & elem : con){
        cout << elem << " ";
    }
    cout << endl;
}

class Point
{
public:
    Point(int ix = 0, int iy = 0)
    : _ix(ix)
    , _iy(iy)
    {
    }

    //计算点到原点的距离
    float getDistance() const
    {
        return hypot(_ix, _iy);
    }

    int getX() const
    {
        return _ix;
    }

    int getY() const
    {
        return _iy;
    }

    ~Point()
    {
    }

    friend std::ostream & operator<<(std::ostream & os,const Point & rhs);   //Point

    friend bool operator<(const Point &lhs, const Point &rhs);  // < 运算符重载

private:
    int _ix;
    int _iy;
};

//由于是自定义模板,需要重载 <<
//同时由于需要访问Point类的私有成员,因此在Point类中需要把该函数声明为友元
std::ostream & operator<<(std::ostream & os,const Point & rhs){
    os << "(" << rhs._ix << "," << rhs._iy << ")";
    return os;
}

//第一种 -- 模板的特化

//第二种 -- 函数对象

//第三种 -- 运算符重载
bool operator<(const Point & lhs,const Point & rhs){
    cout << "bool operator<" << endl;
    if(lhs.getX() < rhs.getX())
        {
            return true;
        }else if(lhs.getX() == rhs.getX()){
            if(lhs.getY() < rhs.getY()){
                return true;
            }else{
                return false;
            }
        }
        else    //lhs.getX() > rhs.getX()
        {
            return false;
        }
}



void test0(){
    set<Point> number = {
        Point(1, 2),
        Point(-1, 2),
        Point(1, 4),
        Point(1, 2),
        Point(1, -2),
        Point(3, 2),
    };

    display(number);
}

int main()
{
    test0();       
    return 0;
}  

补充

如果模板的特化运算符重载同时存在

优先调用 模板的特化

在这里插入图片描述


完整版代码

//setPoint_three.cc

#include <math.h>
#include <iostream>
#include <set>

using std::cout;
using std::endl;
using std::set;

template <typename Container>
void display(const Container &con)
{
    for(auto &elem : con)
    {
        cout << elem << "  ";
    }
    cout << endl;
}

class Point
{
public:
    Point(int ix = 0, int iy = 0)
    : _ix(ix)
    , _iy(iy)
    {
    }

    //计算点到原点的距离
    float getDistance() const
    {
        return hypot(_ix, _iy);
    }

    int getX() const
    {
        return _ix;
    }

    int getY() const
    {
        return _iy;
    }

    ~Point()
    {
    }

    friend std::ostream &operator<<(std::ostream &os, const Point &rhs);
    friend bool operator<(const Point &lhs, const Point &rhs);
    friend struct ComparePoint;

private:
    int _ix;
    int _iy;
};

std::ostream &operator<<(std::ostream &os, const Point &rhs)
{
    os << "(" << rhs._ix
       << ", " << rhs._iy
       << ")";

    return os;
}

bool operator<(const Point &lhs, const Point &rhs)
{
    cout << "bool operator<" << endl;
    if(lhs.getDistance() < rhs.getDistance())
    {
        return true;
    }
    else if(lhs.getDistance() == rhs.getDistance())
    {
        if(lhs._ix < rhs._ix)
        {
            return true;
        }
        else if(lhs._ix == rhs._ix)
        {
            if(lhs._iy < rhs._iy)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}

struct ComparePoint
{
    bool operator()(const Point &lhs, const Point  &rhs) const
    {
        cout << "struct ComparePoint" << endl;
        if(lhs.getDistance() < rhs.getDistance())
        {
            return true;
        }
        else if(lhs.getDistance() == rhs.getDistance())
        {
            if(lhs._ix < rhs._ix)
            {
                return true;
            }
            else if(lhs._ix == rhs._ix)
            {
                if(lhs._iy < rhs._iy)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }

    }
};

#if 0
namespace std
{
template <class T>
struct less
{
    bool operator()(const T &lhs, const T &rhs) const
    {
        return lhs < rhs;
    }
};
}//end of namespace std
#endif

//命名空间的扩展
namespace  std
{

template <>
struct less<Point>//模板的特化
{
    bool operator()(const Point &lhs, const Point &rhs) const
    {
        cout << "template<> struct less" << endl;
        if(lhs.getDistance() < rhs.getDistance())
        {
            return true;
        }
        else if(lhs.getDistance() == rhs.getDistance())
        {
            if(lhs.getX() < rhs.getX())
            {
                return true;
            }
            else if(lhs.getX() == rhs.getX())
            {
                if(lhs.getY() < rhs.getY())
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }
};

}//end of namespace std
 
void test()
{
    set<Point> number = {
    /* set<Point, ComparePoint> number = { */
        Point(1, 2),
        Point(-1, 2),
        Point(1, 4),
        Point(1, 2),
        Point(1, -2),
        Point(3, 2),
    };
    display(number);
}

int main(int argc, char *argv[])
{
    test();
    return 0;
}
### Vue 中实现地图功能的概述 在现代 Web 开发中,Vue 是一种流行的前端框架,用于构建用户界面。结合地图服务 API(如百度地图、Google 地图或其他第三方地图服务),可以在 Vue 应用程序中轻松实现地图展示与交互。 以下是基于 Vue 的地图功能实现方法及其示代码: --- #### 1. 安装依赖并引入地图 API 脚本 为了使用百度地图的功能,在项目中需要先引入百度地图 JavaScript API 文件 `bmap_offline_api_v3.0.min.js`[^1]。可以通过 `<script>` 标签手动加载或者通过 npm 包管理工具安装对应的插件。 如果选择在线方式加载脚本,则可以直接在 HTML 文件头部加入如下代码: ```html <script type="text/javascript" src="https://api.map.baidu.com/api?v=3.0&ak=您的API密钥"></script> ``` 对于离线开发环境,也可以下载官方提供的 SDK 并将其放置于本地服务器路径下再引用。 --- #### 2. 初始化地图组件 创建一个简单的 Vue 组件来承载地图实化逻辑。下面展示了如何定义模板结构以及设置初始参数的过程。 ##### 示代码:Vue 配置地图显示区域 ```vue <template> <div id="allmap" style="width: 100%; height: 500px;"></div> </template> <script> export default { name: 'BaiduMap', mounted() { this.initMap(); }, methods: { initMap() { const map = new BMapGL.Map('allmap'); // 创建 Map 实 map.centerAndZoom(new BMapGL.Point(116.28019, 40.049191), 19); // 设置中心点坐标和缩放级别 map.enableScrollWheelZoom(true); // 启动鼠标滚轮放大缩小 map.setHeading(64.5); // 设置角度偏移量 map.setTilt(73); // 设定倾斜度数 } } }; </script> ``` 上述代码片段实现了基本的地图渲染效果,并设置了特定视点位置[^3]。 --- #### 3. 增强用户体验——添加标记物或覆盖层 为了让地图更加实用,通常还需要增加一些额外特性比如标注兴趣点 (POI),绘制多边形边界等等。这里给出一个小子说明怎样向地图添加自定义图标作为地标提示信息框。 ##### 添加 Marker 图标到指定地点 ```javascript const point = new BMapGL.Point(116.28019, 40.049191); const marker = new BMapGL.Marker(point); // 将 Marker 添加至地图对象内部 map.addOverlay(marker); // 可选配置项 - 当点击该 Marked 显示气泡窗口内容 marker.addEventListener("click", function () { alert(`您选择了这个位置 ${point.lng}, ${point.lat}`); }); ``` 以上部分演示了如何动态生成地理实体并与之绑定事件处理器。 --- #### 4. 使用 Setup 语法糖简化逻辑处理 随着 Vue 3 版本发布以来,“Composition API” 成为推荐的新模式之一。“Setup” 函数允许开发者更灵活地组织业务状态管理和副作用控制流。下面是采用此风格改写的版本。 ##### Composition API 改写版 ```vue <template> <div ref="mapContainer" class="map-container"></div> </template> <script lang="ts"> import { onMounted, ref } from 'vue'; export default { setup() { const mapContainer = ref(null); onMounted(() => { if (!mapContainer.value) return; const map = new BMapGL.Map(mapContainer.value as HTMLElement); map.centerAndZoom(new BMapGL.Point(116.28019, 40.049191), 19); map.enableScrollWheelZoom(); const point = new BMapGL.Point(116.28019, 40.049191); const marker = new BMapGL.Marker(point); map.addOverlay(marker); marker.addEventListener('click', () => window.alert(`Position clicked at (${point.lng},${point.lat})`) ); }); return { mapContainer }; } } </script> <style scoped> .map-container { width: 100%; height: 500px; } </style> ``` 这段代码采用了 TypeScript 类型声明支持的同时也体现了响应式编程的优势[^2]。 --- ### 总结 综上所述,借助 Vue 框架能够快速搭建起具备高度可定制性的地图应用解决方案。无论是基础的地图呈现还是高级别的三维场景模拟都可以依靠相应扩展库完成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值