我应该尝试返回阵列,还是有更好的解决方案?

时间:2015-06-04 14:30:22

标签: c++ arrays

学习C ++的人的问题set

  

写一个简短的程序来模拟从塔上掉下来的球。首先,应该要求用户以米为单位的塔的初始高度。假设正常重力(9.8 m / s2),并且球没有初始速度。让程序在0,1,2,3,4和5秒后输出球高于地面的高度。球不应该在地下(高度0)。

在开始使用C ++之前,我有一个合理但主要是自学成才的Java知识。所以看问题似乎应该分成

  • 输入课程
  • 输出类
  • 计算类
  • 物理常数类(由问题设定者推荐)
  • 控制器('主要')类

输入类会询问用户一个起始高度,该起始高度将传递给控制器​​。控制器会向计算类提供此秒和数秒(5),这将创建结果数组并将其返回给控制器。控制器会将结果数组交给输出类,然后将它们打印到控制台。

我会将实际代码放在底部,但可能不需要它。

您可能已经看到问题,尝试返回一个数组。我没有问如何解决这个问题,有一个解决方法herehere。我问,问题是设计糟糕的结果?出于性能,维护或样式的原因,我的程序应该采用不同的结构,以便我不会尝试返回像对象这样的数组吗?

这是代码(与尝试返回数组不同);

的main.cpp

/*
 * Just the main class, call other classes and passes variables around
 */
#include <iostream>
#include "dropSim.h"
using namespace std;

int main()
{
    double height = getHeight();
    int seconds = 5;
    double* results = calculateResults(height, seconds);
    outputResults(results);
    return 0;
}

getHeight.cpp

/*
 *  Asks the user for a height from which to start the experiment
 *  SI units
 */
#include <iostream>
using namespace std;

double getHeight()
{
    cout << "What height should the experiment start at; ";
    double height;
    cin >> height;
    return height;
}

calculateResults.cpp

/*
 * given the initial height and the physical constants, the position of the ball
 * is calculated at integer number seconds, beginning at 0
 */

#include "constants.h"
#include <cmath>
#include <iostream>
using namespace std;

double getPosition(double height, double time);

double* calculateResults(double height, int seconds)
{

    double positions[seconds + 1];
    for(int t = 0; t < seconds + 1; t++)
    {
        positions[t] = getPosition(height, t);
    }
    return positions;
}

double getPosition(double height, double time)
{
    double position = height - 0.5*constants::gravity*pow(static_cast<double>(time), 2);
    if( position < 0) position = 0;
    //Commented code is for testing
    //cout << position << endl;
    return position;
}

outputResults.cpp

/*
 *      Takes the array of results and prints them in an appropriate format
 */


#include <iostream>
#include <string>
#include <sstream>

using namespace std;

void outputResults(double* results){
    string outputText = "";
    //The commented code is to test the output method
    //Which is working
    //double results1[] = {1,2,3,4,5};
    //int numResults = sizeof(results1)/sizeof(results1[0]);
    int numResults = sizeof(results)/sizeof(results[0]);
    //cout << numResults; //= 0 ... Oh
    for(int t = 0; t < numResults; t++)
    {
        ostringstream line;
        line << "After " << t << " seconds the height of the object is " << results[t] << "\r";
        outputText.append(line.str());

    }
    cout << outputText;
}

最后是几个标题; dropSim.h

/*
 * dropSim.h
 */

#ifndef DROPSIM_H_
#define DROPSIM_H_

double getHeight();

double* calculateResults(double height, int seconds);

void outputResults(double* results);

#endif /* DROPSIM_H_ */

constants.h

/*
 *      Contains physical constants relevant to simulation.
 *      SI units
 */

#ifndef CONSTANTS_H_
#define CONSTANTS_H_

namespace constants
{
    const double gravity(9.81);
}

#endif /* CONSTANTS_H_ */

3 个答案:

答案 0 :(得分:7)

我会说你过度设计了一个解决一个小问题的大解决方案,但要回答你的具体问题:

  

我的程序是否应该以不同的方式构建,出于性能,维护或样式的原因,这样我就不会尝试返回像对象一样的数组?

返回类似数组的对象很好。但这并不意味着返回一个数组,也不意味着用new分配原始内存。

并且它也不限于返回值。当你开始使用C ++时,最好不要忘记它有内置数组。大多数情况下,您应该使用std::vectorstd::array(或其他线性集合,例如std::deque)。

内置数组通常应被视为专用项,主要用于与C兼容,不适合日常使用。

但是,可能值得考虑以与标准库中的算法相同的方式编写计算。这意味着编写代码以接收到目标的迭代器,并将其输出写入迭代器指定的位置。

我可能将高度和时间打包在一起作为一组输入参数,并且有一个根据这些参数生成输出的函数:

struct params {
    double height;
    int seconds;
};

template <class OutIt>
void calc_pos(params const &p, OutIt output) { 
    for (int i=0; i<p.seconds; i++) {
        *output = get_position(p.height, i);
        ++output;
    }
}

与标准库的其余部分一起使用时更加清晰:

std::vector<double> results;

calc_pos(inputs, std::back_inserter(results));

如果你愿意,你可以更进一步 - 标准库有很多可以帮助解决这个问题。你的calc_pos只是用连续的时间值重复调用另一个函数。您可以(例如)使用std::iota生成连续的时间,然后使用std::transform生成输出:

std::vector<int> times(6);

std::iota(times.begin(), times.end(), 0);

std::vector<double> distances;

std::transform(times.begin(), times.end(), compute_distance);

这计算distances作为在给定时间段之后下降的距离而不是高于地面的高度,但是给定初始高度,计算两者之间的差异是非常微不足道的:

double initial_height = 5;

std::vector<double> heights;

std::transform(distances.begin(), distances.end(), 
    std::back_inserter(heights),
    [=](double v) { return max(initial_height-v, 0); });

至少就目前来说,这不会试图计算球撞击地面时的弹跳 - 它只是假设球在撞击地面时会立即停止。

答案 1 :(得分:3)

您应该摆脱自我分配double *并使用std::vector<double>代替。它不难学习,也是现代C ++的基本步骤

答案 2 :(得分:1)

这就是我解决问题的方法:

#include <cmath>
#include <iostream>
#include <iomanip>

using std::cin;
using std::cout;
using std::endl;
using std::sqrt;
using std::fixed;
using std::setprecision;
using std::max;
using std::setw;

static const double g = 9.81;

class Calculator {
public:
   Calculator(double inh) : h(inh)
   {
   }

   void DoWork() const {
      double tmax = sqrt(h / ( g / 2));
      for (double t=0.0; t<tmax; t+=1.0) {
         GenerateOutput(t);
      }
      GenerateOutput(tmax);
   }
private:
   void GenerateOutput(double t) const {
      double x = g * t * t / 2;
      double hremaining = max(h - x, 0.0);     
      cout << fixed << setprecision(2) << setw(10) << t;
      cout << setw(10) << hremaining << endl;
   }

   double h;
};

int main() {
   double h(0.0);

   cout << "Enter height in meters: ";
   cin >> h;
   if (h > 0.0) {
      const Calculator calc(h);
      calc.DoWork();  
   } else {
      return 1;
   }

   return 0;
}