gpt4 book ai didi

C++ 入门第 6 次练习 10.8

转载 作者:行者123 更新时间:2023-11-28 00:19:26 25 4
gpt4 key购买 nike

你可以描述一个简单的列表如下:

  • 简单列表可以包含零个或多个特定类型的项目。
  • 您可以创建一个空列表。
  • 您可以向列表中添加项目。
  • 您可以判断列表是否为空。
  • 您可以判断列表是否已满。
  • 您可以访问列表中的每个项目并对其执行一些操作。

如您所见,这个列表真的很简单;例如,它不允许插入或删除。设计一个List类来表示这个抽象类型。你应该提供一个list.h带有类声明的头文件和带有类方法的 list.cpp 文件实现。您还应该创建一个利用您的设计的简短程序。

保持列表规范简单的主要原因是为了简化此编程练习。您可以将列表实现为数组,或者,如果您熟悉数据类型,作为链表。但是公共(public)接口(interface)不应该依赖于你的选择。也就是说,公共(public)接口(interface)不应该有数组索引,指向节点的指针,等等。它应该用创建列表、向列表添加项目等一般概念来表达。处理访问每个项目和执行的通常方式一个 Action 是使用一个以函数指针作为参数的函数:

void visit(void (*pf)(Item &));

这里pf指向一个函数(不是成员函数),它引用了Item参数,其中 Item 是列表中项目的类型。应用 visit() 函数此函数适用于列表中的每个项目。您可以使用 Stack 类作为一般指南。


我想知道的是为什么要使用指向函数的指针?使用普通成员函数和使用函数指针作为参数的函数有什么区别? (在这种情况下,使用 void visit(void (*pf)(Item &)))?

最佳答案

函数指针

假设您有一个函数,它接受一个数字并将其平方并返回它。您有一个列表,您希望其中的每个成员都平方。你是怎么做到的?

  1. 您要么编写另一个接受数组的函数,遍历它并将每个元素转换为它的正方形。
  2. 你有一个接受数组的函数和一个可以转换单个元素的函数。您将该函数应用于数组的每个元素。

两者执行相同的任务。您可能认为前一种情况更容易实现。毕竟您不必处理函数指针。

但是,如果您有 20 个函数,可以将单个参数传递给它们,它们可以加倍、加倍、加倍、加倍、加倍、加倍等。如果您遵循第一种方法,则必须编写 20 个不同的函数(名称可能不同)。但是现在后者是有道理的。您只需声明各个函数。并通过指针传递数组和 20 个函数中的任何一个来调用转换器函数来完成您的任务。

一个例子是 C++ STL 中的 std::transform

工作内容:

#include <iostream>
#include <vector>

typedef double (*function)(double);

void transformer(std::vector<double>& to_transform, function f)
{
for(auto it = to_transform.begin(); it != to_transform.end(); ++it)
*it = f(*it);
}

void print(const std::vector<double>& v)
{
std::cout << "[ ";
for(double val : v)
std::cout << val << " ";
std::cout << "]" ;
}

double f1(double a) { return a*2; }
double f2(double a) { return a*3; }
double f3(double a) { return a/2; }
double f4(double a) { return a*a*a; }

int main() {
std::vector<double> array = { 2.3, 5.6, 4.5, 7.8, 2.3 };
std::vector<function> function_ptrs = { &f1, &f2, &f3, &f4 };
std::size_t val ;
std::cout << "The original : " ;
print(array);
std::cout << "\nChoose a function (1-4) : ";
std::cin >> val;
std::cout << "The array after applying function " << val << " is : ";
transformer(array, function_ptrs[(val - 1) % function_ptrs.size()]);
print(array);
return 0;
}

我假设您有一个 C++11 兼容的编译器。上面的代码有 4 个函数,它们接收一个 double 并以某种方式转换它。 transformer 函数将这样的函数应用于 double vector 。函数指针也存储在一个 vector 中——是的,一个函数指针数组。当通过索引访问普通元素时,可以调用这些函数。选择一个选项后,transformer 元素将在 double vector 上调用并执行适当的函数。

您可以使用模板(而不是固定 double )和使用来自 STL 的 std::transform 进一步改进它。

C++11 Lambda 表达式

此外,对于 C++11,您应该更喜欢 lambda 而不是函数指针。 Lambdas 写成

[ ... capture list ... ] ( params ) -> return_type (optional) { body }

使用 lambda 的解决方案是这样的:

#include <iostream>
#include <algorithm>
#include <vector>

template <typename T>
void print(const std::vector<T>& v)
{
std::cout << "[ ";
for(T val : v)
std::cout << val << " ";
std::cout << "]" ;
}

int main() {
std::vector<double> array = { 2.3, 5.6, 4.5, 7.8, 2.3 };
std::cout << "The original : " ;
print(array);
std::cout << "\nThe array after transforming : " ;
std::transform(array.begin(), array.end(), array.begin(),
[](double x) { return x * x; });
print(array);
return 0;
}

函数对象

你可以声明你自己的类,它只重载 () 运算符(这使得对象可调用)并且做与函数指针相同的工作(可以传递给函数并被调用)即在这种情况下,类看起来像:

class double_the_value
{
double operator()(double val) const { return val * 2.0 ; }
};

double_the_value f ;
std::cout << f(3.0) ; // outputs 6.0

实际用法是 std::unordered_map 容器,如果您使用自己的类类型作为键,您将需要提供一个键散列器——它可以是一个函数对象。 this 详细说明了这一点回答。

关于C++ 入门第 6 次练习 10.8,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28298913/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com