0

新手/学生程序员,试图找出这里出了什么问题。

我有一个“腿”类和一个“路线”类,其中路线是通过将较早的路线对象添加到腿对象来构建的。

路由类有两个构造函数;一种用于使用一条支路创建初始路线,另一种用于使用前一条路线和另一条支路构建后续路线。

一切似乎都很好

  • 使用仅腿构造函数创建第一条路线

  • 使用 leg+route 构造函数创建第二条路线

  • 使用 leg+route 构造函数创建第三条路线

但是,如果我尝试以与创建第二个和第三个相同的方式创建第四个路由,则程序将编译,但当程序到达第一个路由对象时会崩溃。

代码如下:

/////////////////////////////
/* includes and namespaces */
/////////////////////////////


#include <iostream>
using std::cin;
using std::cout;
using std::endl;

#include <ostream>
using std::ostream;


#include <cstdlib> // use for: atof(), atoi()




///////////////////////
/* const definitions */
///////////////////////




////////////////////////
/* struct definitions */
////////////////////////


///////////////////////
/* class definitions */
///////////////////////

class Route;

class Leg
{
  private:
    const char* const startCity;
    const char* const endCity;
    const int length;


  public: 
    Leg( const char* const, const char* const, const int );
    friend void printLeg( ostream&, const Leg&);


    friend void printRoute( ostream&, const Route& );

};

class Route
{
  private:
    const Leg** legsPtrArray;
    const int totalLegs;


  public:
    Route( const Leg& );
    Route( const Route&, const Leg& );
    Route( const Route&);  
    ~Route();

    friend void printRoute( ostream&, const Route& );



};


/////////////////////////
/* function prototypes */
/////////////////////////




///////////////////
/* main function */
///////////////////

int main()
{


  Leg Leg1( "San Francisco", "Reno", 218 );

  Leg Leg2( "Reno", "Salt Lake City", 518 );

  Leg Leg3( "Salt Lake City", "Kansas City", 604 );

  Leg Leg4( "Kansas City", "Indianapolis", 482 );

  Leg Leg5( "indianapolis", "NYC", 709 );

  cout << "Legs loaded, press [enter] to print each leg" << endl;

  cin.get();

  cout << "Leg 1: " << endl << endl;
  printLeg( cout, Leg1 );
  cin.get();

  cout << "Leg 2: " << endl << endl;
  printLeg( cout, Leg2 );
  cin.get();

  cout << "Leg 3: " << endl << endl;
  printLeg( cout, Leg3 );
  cin.get();  

  cout << "Leg 4: " << endl << endl;
  printLeg( cout, Leg4 );
  cin.get();  

  cout << "Leg 5: " << endl << endl;
  printLeg( cout, Leg5 );
  cin.get();

  cout << "Building complete route: " << endl << endl;

  Route Route1( Leg1 );

  Route Route2( Route1, Leg2 );

  Route Route3( Route2, Leg3 );

  cout << "Route built! Press [enter] to print" << endl << endl;

  cin.get();

  printRoute( cout, Route3);

  /*

  Route Route4( Route3, Leg4 );

  cout << "Route built! Press [enter] to print" << endl << endl;

  cin.get();

  printRoute( cout, Route4);

  */

  /*

  Route Route5( Route4, Leg5 );

  cout << "Route built! Press [enter] to print" << endl << endl;

  cin.get();

  printRoute( cout, Route5);

  */

  cout << endl;

  cout << "Press [enter] to quit " << endl;

  cin.get();


}

//////////////////////////
/* function definitions */
//////////////////////////


Leg::Leg( const char* const startCityToLoad, const char* const endCityToLoad, const int lengthToLoad )
 : startCity( startCityToLoad ), endCity( endCityToLoad ), length( lengthToLoad )
{

}

void printLeg( ostream& out, const Leg& legToPrint )
{
  out << "Leg start city: " << legToPrint.startCity << endl;
  out << "Leg end city: " << legToPrint.endCity << endl;
  out << "Leg length: " << legToPrint.length << " miles" << endl;

}

Route::Route( const Leg& legToAdd)
: totalLegs( 1 ), legsPtrArray ( new const Leg*[totalLegs] )
{

  legsPtrArray[0] = &legToAdd;

}

Route::Route( const Route& subRoute, const Leg& legToAdd)
: totalLegs( subRoute.totalLegs + 1 ), legsPtrArray ( new const Leg*[totalLegs] )
{

  for (int i = 0; i < subRoute.totalLegs ; i++)
  {
    legsPtrArray[i] = subRoute.legsPtrArray[i];

  }

  legsPtrArray[subRoute.totalLegs] = &legToAdd;

}

Route::Route( const Route& routeCopy )
: totalLegs( routeCopy.totalLegs ), legsPtrArray ( routeCopy.legsPtrArray )
{

}

Route::~Route()
{
  delete[] legsPtrArray;
}

void printRoute( ostream& out, const Route& routeToPrint )
{

  out << "Route: from " 
    << routeToPrint.legsPtrArray[0]->startCity 
    << " to "
    << routeToPrint.legsPtrArray[0]->endCity 
  ; 

  for (int i = 1; i < routeToPrint.totalLegs; i++)
  {
    out 
      << " to " 
      << routeToPrint.legsPtrArray[i]->endCity;
  }

  out << endl << endl;



  int routeLength = 0;

  for (int i = 0; i < routeToPrint.totalLegs; i++)
  {
    routeLength = 
      routeLength + routeToPrint.legsPtrArray[i]->length;

  }

    out << "Route Length: " << routeLength << " miles" << endl;

}

照原样,这编译并运行良好。

如果我删除周围的评论

  /*

  Route Route4( Route3, Leg4 );

  cout << "Route built! Press [enter] to print" << endl << endl;

  cin.get();

  printRoute( cout, Route4);

  */

程序成功创建了腿,然后在到达第一条路线时崩溃。

我知道我必须这样做......指针有问题,但我不知道是什么以及为什么会导致程序以这种特殊方式崩溃。

如果有人比我更有洞察力,我将不胜感激。

4

1 回答 1

0

您的问题是构造初始化列表的元素的顺序。

尝试在 Route 类中交换成员声明。它应该如下所示:

class Route
{
  private:
  const int totalLegs; // totalLegs comes first
  const Leg** legsPtrArray; // array comes next

我刚刚验证它可以在我的系统上运行。

要了解原因,请看这里

编辑:添加我得到的输出:

Leg 5:

Leg start city: indianapolis
Leg end city: NYC
Leg length: 709 miles

Building complete route:

Route built! Press [enter] to print


Route: from San Francisco to Reno to Salt Lake City to Kansas City

Route Length: 1340 miles
Route built! Press [enter] to print


Route: from San Francisco to Reno to Salt Lake City to Kansas City to Indianapolis

Route Length: 1822 miles

Press [enter] to quit

编辑:解释这个怪癖......

任何 C++ 类只能有一个析构函数,但可以有多个构造函数。

现在,析构函数的要求之一是它必须以与构造相反的顺序销毁对象(原始或其他)的字段。

这意味着必须只有一个明确定义的构造顺序。这意味着,字段的构造顺序不能依赖于它们在构造函数初始化列表中指定的顺序;因为一个类可以有多个构造函数,每个构造函数都指定它们自己在初始化列表中的字段顺序。所以编译器使用类定义中字段的顺序作为初始化顺序,而不是初始化列表中的顺序。

在您的程序中,基本上数组legsPtrArray在其长度之前被初始化totalLegs(因为它们在程序中指定的顺序)。的未定义值totalLegs会是一些垃圾,导致数组初始化失败。

于 2013-09-30T05:18:31.720 回答