C++ - 泛型指针使用示例

这篇博客展示了如何使用C++模板函数实现`find`和`find_pre_version`两个查找算法,并在整型数组、双精度浮点型数组和字符串数组中应用。示例代码包括对`vector`和`list`容器的查找操作,最后运行结果验证了算法的正确性。

等后面学完了再来细写,先备份个代码。
参考:

  1. 《Essential C++》
#include <iostream>
#include <vector>
#include <list>
using namespace std;

template <typename elemType>
elemType *find_pre_version(const elemType *array, const elemType *sentinel, const elemType &value);
// const情况会导致传入string指针时报错

template <typename IteratorType, typename elemType>
IteratorType find(IteratorType first, IteratorType last, const elemType &value)
{
    for (; first != last; ++first)
    {
        if (*first == value)
        {
            return first;
        }
    }
    return last;
}

template <typename elemType>
elemType *find_pre_version(elemType *first,elemType *last, const elemType &value)
{
    if (!first || !last)
    {
        return 0;
    }
    for (; first != last; ++first)
    {
        if (*first == value)
        {
            return first;
        }
    }
    return 0;
}


template <typename elemType>
inline elemType *begin(vector<elemType> &vec)
{
    return vec.empty() ? 0 : &vec[0];
}

template <typename elemType>
inline elemType *end(vector<elemType> &vec)
{
    return vec.empty() ? 0 : &vec[vec.size()];
}

int main()
{
    int ia[8] = {1, 2, 3, 4, 5, 6, 7, 8};
    double da[8] = {1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5};
    string sa[8] = {"a0", "b1", "c2", "d3", "e4", "f5", "g6", "h7"};
    int *pi = find(ia, ia + 8, ia[3]);
    double *pd = find(da, da + 8, da[3]);
    string *ps = find(sa, sa + 8, sa[3]);
    cout << "*pi: " << *pi << ", *pd: " << *pd << ", *ps: " << *ps << endl;

    vector<int> via(ia, ia + 8);
    vector<int>::iterator it;
    it = find(via.begin(), via.end(), 5);
    if(it != via.end()) {
        cout << "*vector_iter: " << *it << endl;
    }
    
    int *vpi = find_pre_version(begin<int>(via), end<int>(via), 5);
    cout << "*vpi: " << *vpi << endl;

    list<int> lia(ia, ia+8);
    list<int>::iterator iter;
    iter = find(lia.begin(), lia.end(), 5);
    if(iter != lia.end()) {
        cout << "*list_iter: " << *iter << endl;
    }

    return 0;
}

输出结果:

*pi: 4, *pd: 2.5, *ps: d3
*vector_iter: 5
*vpi: 5
*list_iter: 5
<think> 我们正在讨论C++中的指针。根据用户的问题,他想了解C++指针的定义和相关信息。结合站内引用,我们可以知道指针通常指的是`void*`指针,它可以指向任意类的数据,但也会带来类安全的问题。 在C++中,指针(即`void*`)是一种可以存储任意类对象地址的指针。但是,由于它没有类信息,因此不能直接解引用,也不能进行指针算术运算(除非进行强制类转换)。这在需要处理未知类数据时非常有用,比如在底层内存操作、与C语言交互、或者某些库函数(如`malloc`)中。 下面我们根据站内引用和C++知识来详细解释: 1. **定义**:指针C++中就是`void*`类。它不关联任何具体的数据类,因此可以指向任何数据类的对象。例如: ```cpp int a = 10; double b = 3.14; void* p = &a; // 指向int p = &b; // 现在指向double ``` 2. **使用限制**: - 不能直接解引用:因为编译器不知道它指向的数据类,所以必须通过强制类转换来将其转换为具体类指针后才能解引用。 - 不能进行指针算术运算:因为指针算术运算需要知道所指向对象的大小,而`void*`没有类信息,所以无法进行`p++`这样的操作(除非转换为具体类指针)。 3. **应用场景**: - 内存管理函数:如`malloc`和`free`,它们使用`void*`作为返回类和参数类,以便能够处理任意类的内存块。 - 通用接口:例如,在C标准库中的`qsort`函数,它使用`void*`来接收数组的起始地址,从而可以对任何类的数组进行排序。 -C++中,有时用于实现底层的数据结构(如某些自定义的容器)或者与C语言交互。 4. **与模板的对比**:站内引用[2]提到了使用模板来实现,这是一种类安全的方式。例如,使用`std::unique_ptr`模板可以创建指向特定类的智能指针。而`void*`是非类安全的,容易出错。 5. **类转换**:使用`void*`时,必须通过显式类转换来恢复原始类。例如: ```cpp int a = 10; void* p = &a; int* pi = static_cast<int*>(p); // 转换为int指针 std::cout << *pi << std::endl; ``` 6. **风险**:由于`void*`绕过了类系统,错误的使用可能导致未定义行为。例如,将一个`void*`指针转换为错误的类,然后解引用,会导致不可预知的结果。 7. **在C++中的替代方案**:在C++中,通常推荐使用模板、继承和多态(如基类指针)等机制来实现编程,这些方式更加安全。`void*`应仅在需要与C语言交互或进行底层内存操作时使用。 下面是一个示例代码,展示`void*`的使用: ```cpp #include <iostream> int main() { int num = 42; double pi = 3.14159; // 指针可以指向任何类 void* ptr; ptr = &num; // 指向int // 必须转换为int*才能解引用 std::cout << "Integer value: " << *(static_cast<int*>(ptr)) << std::endl; ptr = π // 指向double // 必须转换为double*才能解引用 std::cout << "Double value: " << *(static_cast<double*>(ptr)) << std::endl; return 0; } ``` 输出: ``` Integer value: 42 Double value: 3.14159 ``` 在这个例子中,我们使用同一个`void*`指针先后指向一个整数和一个双精度浮点数,并通过强制类转换来正确解引用。 总结:C++中的指针就是`void*`,它提供了一种通用的指针,可以存储任何类对象的地址。但是,使用它需要谨慎,因为缺乏类安全性。在C++中,应优先考虑使用模板等类安全的编程技术。 §§相关问题§§ 1. 在C++中,如何安全地使用`void*`指针? 2. `void*`指针和模板在编程中的优缺点比较? 3. C++标准库中有哪些地方使用了`void*`? </think>### C++ 指针详解 #### 1. **核心定义** 指针(Generic Pointer)在 C++ 中特指 `void*` 类指针,也称为**万能指针**。其核心特性: - **无类地址**:仅存储内存地址,不关联具体数据类 - **类兼容性**:可指向任意类的数据对象 - **强制解引用**:需显式类转换后才能访问数据 ```cpp int num = 42; double pi = 3.14; void* generic_ptr; // 指针声明 generic_ptr = &num; // 指向 int generic_ptr = π // 指向 double ``` #### 2. **核心特性** | 特性 | 说明 | 示例 | |---------------------|----------------------------------------------------------------------|----------------------------------------------------------------------| | **无类存储** | 仅存储原始地址,不包含类信息 | `void* ptr = malloc(sizeof(int));` | | **强制类转换** | 解引用前必须显式转换 | `int* int_ptr = static_cast<int*>(generic_ptr);` | | **内存操作基础** | 底层内存函数的通用接口 | `memset(generic_ptr, 0, 100);` | | **兼容 C 标准库** | 支持 `malloc/calloc/realloc` 等函数 | `void* buffer = malloc(1024);` | #### 3. **应用场景** **场景 1:通用内存管理** ```cpp // 创建任意类数组 void* create_array(size_t size, size_t elem_size) { return malloc(size * elem_size); } int main() { int* int_arr = static_cast<int*>(create_array(10, sizeof(int))); double* double_arr = static_cast<double*>(create_array(5, sizeof(double))); } ``` **场景 2:函数参数** ```cpp void print_data(void* data, char type) { switch(type) { case 'i': std::cout << *(static_cast<int*>(data)); break; case 'd': std::cout << *(static_cast<double*>(data)); break; } } ``` **场景 3:C/C++ 交互接口** ```cpp // C 语言接口 extern "C" void process_data(void* data, int type_code); // C++ 调用 MyStruct data; process_data(&data, TYPE_STRUCT); ``` #### 4. **类安全对比** | 特性 | 指针 (`void*`) | 模板指针 (`std::unique_ptr<T>`) | |---------------|-------------------------------------|---------------------------------------| | **类安全** | ❌ 需手动类转换,易出错 | ✅ 编译期类检查 | | **内存管理** | 手动管理 (`malloc/free`) | 自动管理 (RAII) | | **可读性** | 低(需额外类信息) | 高(类显式声明) | | **应用场景** | 底层内存操作,跨语言接口 | 类安全的编程 | #### 5. **关键注意事项** 1. **解引用限制** ```cpp void* ptr = &num; // int value = *ptr; // 错误!不能直接解引用 int value = *(static_cast<int*>(ptr)); // 正确 ``` 2. **指针运算禁止** ```cpp void* arr = malloc(10 * sizeof(int)); // arr++; // 错误!void* 不支持算术运算 int* int_arr = static_cast<int*>(arr); int_arr++; // 正确 ``` 3. **类转换风险** ```cpp double d = 3.14; void* vp = &d; int* ip = static_cast<int*>(vp); // 危险!类不匹配 std::cout << *ip; // 输出错误数据 ``` #### 6. **现代 C++ 替代方案** 优先使用安全的技术: ```cpp // 模板替代方案 template <typename T> void safe_print(const T* data) { std::cout << *data; } // 智能指针方案 template <typename T> using GenericSmartPtr = std::unique_ptr<T>; GenericSmartPtr<int> smart_int(new int(42)); ``` > **关键结论**:指针提供底层灵活性,但牺牲类安全。在现代 C++ 中应优先使用模板和智能指针等类安全机制[^1][^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值