这是去年的家庭作业,我决定打开并查看。我跑过调试器,注意到在赋值操作结束时调用了析构函数(重载赋值)。任何人都可以告诉我为什么被称为?我提供了完整的代码,以便它可以在编译器中运行(可以更容易回答问题),但我的问题只是代码的一小部分。
在驱动程序文件中,有一个名为void TestCopyConstructor()
的函数。在此函数中,有一个赋值操作X = "0.12345";
。这会调用其中一个重载的赋值运算符函数MyFloat MyFloat::operator= (const char *Input)
。此函数运行,最后,复制构造函数称为MyFloat MyFloat::MyFloat(const MyFloat & RHS)
。在此函数之后,它返回到调用析构函数的void TestCopyConstructor()
。我试图理解为什么要调用这个析构函数。我意识到这是很多代码,这就是为什么我试图浏览我困惑的特定区域,因为我不知道如何制作这个代码的精简版本。
DRIVER:
#include "MyFloatD.cpp" // Name of your class definition. Use pathname
// if file is not in current working directory.
#include <iostream>
#include <iomanip>
#include <ctype.h>
#include <new>
using namespace std;
void DisplayTestingOptions();
void GetChoice(char& Ch);
void TestInputOperator();
void TestAssignment();
void TestCopyConstructor();
void TestComparison();
void TestPlus();
void TestDestructor();
float CPU_Seconds();
//============================== main =================================
int main()
{
char Choice;
do
{
DisplayTestingOptions();
GetChoice(Choice);
switch ( Choice )
{
case '1': TestCopyConstructor();
break;
case '2': TestAssignment();
break;
case '3': TestInputOperator();
break;
case '4': TestPlus();
break;
case '5': TestComparison();
break;
case '6': TestDestructor();
break;
case 'Q': ; // Exit
};
}
while ( Choice != 'Q' );
return 0;
}
/*********************** SpaceBarToContinue **************************
Displays "Spacebar to continue" and returns 1 iff Spacebar pressed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
int SpaceBarToContinue(const char* Message = " Spacebar continues this test")
{
char Ch;
cout << "\n------------------------------------------"
<< Message;
Ch = cin.get();
return ( Ch == ' ' );
}
/*********************** DisplayTestingOptions ************************
Displays a menu of choices.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void DisplayTestingOptions()
{
const char* TAB = " "; // Provides menu spacing
cout << "\n\n";
cout << "\n----------------------------------"
"------------------------------------\n\n";
cout << TAB << "1) Test copy constructor ";
cout << TAB << "2) Test assignment operator \n";
cout << TAB << "3) Test >> input function ";
cout << TAB << "4) Test + operator \n";
cout << TAB << "5) Test == operator ";
cout << TAB << "6) Test destructor \n";
cout << TAB << "Q) Quit program\n\n";
cout << "Choice? ";
}
/*********************** GetChoice ************************************
Reads a char from the keyboard, provides a redirectable echo and
upcases the char.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void GetChoice(char& Ch)
{
cin >> Ch;
Ch = toupper(Ch);
}
/********************* TestInputOperator ******************************
Allows testing of the member functions ">>" of MyFloat.
The insertion operator << is assumed to be correct.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void TestInputOperator()
{
MyFloat X;
cout << "\n\n>>>>>>>>>>>>> Testing input operator >>>>>>>>>>>>>>>>>\n";
do
{
cout << "\nEnter MyFloat ==> ";
cin >> X;
cout << "\nAfter the read, X = '" << X << "'\n\n";
}
while ( SpaceBarToContinue() );
if (cin.peek() != EOF)
cin.ignore(1000, '\n');
}
/********************* TestAssignment *********************************
Allows testing of the member function "=" of MyFloat. If a deep copy
assignment operator has not been written, the code below will give
unexpected output.
This routine assumes that input and output functions for MyFloats
have been written and debugged.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void TestAssignment()
{
MyFloat X(10), Y(10);
cout << "\n\n------------ Testing '=' for MyFloats --------------------\n\n";
X = "0.1234567890";
Y = X; // This must be a deep copy
X = "0.0"; // Or this will change Y!
cout << "\nAfter the assignments, X = \"0.1234567890\", Y = X, and X = 0.0, "
<< "Y = " << Y << endl;
}
/********************* TestPlus ***************************************
Allows testing of the member function operator+. At the present time,
it allows testing only of addition for MyFloats that have the default
length.
NOTE: Calls two of the copy constructors. The copy constructor also
needs to be working correctly for + to work.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void TestPlus()
{
MyFloat X(12), Y, Sum;
cout << "\n\n++++++++++++++++ Testing \"+\" for MyFloat ++++++++++++++++\n"
<< " (Do not use leading zero)\n";
do
{
cout << "\nEnter X ==> ";
cin >> X;
cin.ignore(1000, '\n'); // Discard all chars in input stream.
cout << "\nEnter Y ==> + ";
cin >> Y;
cin.ignore(1000, '\n'); // Discard all chars in input stream.
cout << " ";
for ( int k = 1; k <= X.Digits() + 3 || k <= Y.Digits() + 3 ; ++k )
cout << '-';
cout << "\n ";
Sum = X + Y;
cout << Sum << "\n\n";
}
while ( SpaceBarToContinue() );
}
/********************* TestCopyConstructor ****************************
Allows testing of the copy constructor that is called automatically
under certain circumstances.
Note that that the default constructor and the overloaded "=" operator
must also be working properly.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void TestCopyConstructor()
{
MyFloat X; // Default constructor called
X = "0.12345"; // Overloaded "=" operator called
MyFloat Y = X; // Copy constructor called
X = "0.0";
cout << "\n\n============ Testing copy constructor ================\n\n";
cout << "NOTE: This function also calls default constructor and '='operator. \n\n\n";
cout << "After 'X = 0.0', Y = " << Y << "\nNote that Y should be 0.12345\n";
}
/********************* TestComparison *********************************
Allows testing of the member function operator+. At the present time,
it allows testing only of addition for MyFloats that have the default
length.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void TestComparison()
{
MyFloat A, B, Sum;
cout << "\n\n== == == == == Testing \"== \" for MyFloat == == == == == \n\n";
cout << "MyFloat variables have maximum length of " << A.MaxDigits() << endl;
do
{
cout << "\nEnter A ==> ";
cin >> A;
cout << "\nEnter B ==> ";
cin >> B;
cout << "\n (A == B) is " << ((A == B) ? "TRUE " : "FALSE ") << endl;
}
while ( SpaceBarToContinue() );
}
/********************* TestDestructor **********************************
Tests to see if the class destructor has been correctly written. If not
this program may crash.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void TestDestructor()
{
const unsigned long REPETITIONS = 70000;
for ( unsigned long N = 1; N <= REPETITIONS; ++N )
{
MyFloat X(10000); // Create 1000 digit MyFloat
} // X goes out of scope at each repetition
// If the destructor is not correct, each repetition of the
// loop above will caused some memory leak and the call to
// new below will fail.
int* A = new int[120];
if ( A == NULL )
cout << "\n\nYour memory has leaked away!\n";
else
{
delete [] A;
cout << "\n\n~~~~~~~~~~~~~~ destructor is OK! ~~~~~~~~~~~~~~~\n";
}
SpaceBarToContinue(" spacebar to continue");
}
和它自己的类:
/******************************************************************
----------------------Class Breakdown----------------------------
Data Members:
-enum (Default Size) sets the size of the MyFloat to 10 by default if no
size is specified
-Char *Number points at array being dynamically allocated in memory
-NumberOfDigits represents the length of the current float
-MaxNumberOfDigits represents the longest length that that particular
object can hold
Member Functions:
-MyFloat(const MyFloat & RHS) copy constructor allows usuer to initialize
new object with another object, by placing it in the parameter list
-MyFloat() is default constructor, initializes objects at MaxSize of 10
-MyFloat(unsigned int Input) standard constructor allows user to create
MyFloat of any size by placing a numerical value in the parameter list
-int Digits() returns size of number currently stored in object
-int MaxDigits() returns the maximum size allowed in current object
-MyFloat operator= (const char *Input) overloaded assignemnt operator
to work with setting an object equal to a literal string (X="0.004")
-MyFloat operator= (const MyFloat &X) overloaded assignent operator to work
with setting an object equal to another object
-int operator== (const MyFloat &x) overloaded comparison operator
-MyFloat operator+ (MyFloat X) overloaded addition operator
-int operator> (MyFloat x) overloaded greater than comparison operator
-friend ostream& operator<< (ostream &Out, const MyFloat & X)
overloaded insertion operator, so user can cout << X
-friend istream& operator>> (istream &In, MyFloat & X)
overloaded extraction operator, so user can cin >> X
********************************************************************/
#include <iostream>
#include <ctype.h>
using namespace std;
class MyFloat
{
enum {DefaultSizeTen=10};
char *Number;
int NumberOfDigits;
int MaxNumberOfDigits;
public:
~MyFloat();
MyFloat(const MyFloat & RHS);
MyFloat();
MyFloat(unsigned int Input);
int Digits();
int MaxDigits();
MyFloat operator= (const char *Input);
MyFloat operator= (const MyFloat &X);
int operator== (const MyFloat &x);
MyFloat operator+ (const MyFloat &X);
int operator> (const MyFloat &x);
friend ostream& operator<< (ostream &Out, const MyFloat & X);
friend istream& operator>> (istream &In, MyFloat & X);
};
/********************* MyFloat Destructor ***************************
Action: Deletes the memory being pointed to by the pointer Number;
Parameters:
IN: none
OUT: none
Returns: none
Preconditions: Number has to be pointing at memory, or else error
occur
*******************************************************************/
MyFloat::~MyFloat()
{
delete Number;
}
/********************* MyFloat Copy Constructor *********************
Action: Initializes an object of MyFloat to be equal to any object being
passed in via parameter list
Parameters:
IN: none
OUT: const MyFloat & RHS - float being getting copied
Returns: none
Preconditions: must be of same data type - MyFloat
*******************************************************************/
MyFloat::MyFloat(const MyFloat & RHS)
{
MaxNumberOfDigits=RHS.MaxNumberOfDigits;
NumberOfDigits=RHS.NumberOfDigits;
Number = new (nothrow) char[RHS.NumberOfDigits+1]; //+1 for overflow
if (Number != NULL)
{
for (int i=0; i<=RHS.NumberOfDigits-1; ++i)
{
Number[i]=RHS.Number[i];
}
}
else
NumberOfDigits=0;
}
/********************* MyFloat Default Constructor *******************
Action: Sets NumberOfDigits to 10 and places 0 in all elements of array
being pointed to by *Number
Parameters:
IN: none
OUT: none
Returns: none
Preconditions: none
*******************************************************************/
MyFloat::MyFloat()
{
MaxNumberOfDigits=DefaultSizeTen;//set MaxNumberOfDigits to default size of 10
NumberOfDigits = 0;
Number = new (nothrow) char[MaxNumberOfDigits+1]; //+1 for overflow
if (Number != NULL)
{
for (int i=0; i<=MaxNumberOfDigits; ++i)
{
Number[i]=0;
}
}
}
/********************* MyFloat Standard Constructor *******************
Action: Sets NumberOfDigits to be equal to whatever user places inside of
the paramter list
Parameters:
IN: unsigned int Input
OUT: none
Returns: none
Preconditions: Input must be int and not negative
*******************************************************************/
MyFloat::MyFloat(unsigned int Input)//Constructor that zeros out Number[] and NumberOfDigits
{
MaxNumberOfDigits=Input;
NumberOfDigits=0;
Number = new (nothrow) char[MaxNumberOfDigits+1];
if (Number != NULL)
{
for (int i=0; i<=MaxNumberOfDigits; ++i)
{
Number[i]=0;
}
}
}
/********************* Digits() ********************************
Action: Simply returns NumberOfDigits to main
Parameters:
IN: none
OUT: none
Returns: returns the NumberOfDigits
Preconditions: none
*******************************************************************/
int MyFloat::Digits()
{
return NumberOfDigits;
}
/********************* MaxDigits() ********************************
Action: Returns MAXDIGIT to main
Parameters:
IN: none
OUT: none
Returns: returns MAXDIGIT
Preconditions: none
*******************************************************************/
int MyFloat::MaxDigits()//Return MAXDIGIT or MaxNumberOfDigits?
{
return MaxNumberOfDigits;
}
/********************* operator=() ********************************
Action: Overloads the assignment operator to allow a string to be stored
in the MyFloat data type, by dynamically allocating memory for a new
array
Parameters:
IN: none
OUT: Const char *Input, which points to the string being assigned to MyFloat
data type
Returns: *this
Preconditions: Assumes incoming string was typed with leading '0' and '.',
these are skipped when storing the string in the MyFloat data type
Number isn't stored if decimal isn't present
*Modified overloaded = function from solution set, since my original
function had some errors
*******************************************************************/
MyFloat MyFloat::operator= (const char *Input)
{
int CounterForInput = 0, CounterForNumber = 0, Length = 0, Temp = 0;
NumberOfDigits = 0;
/* SKIP PAST LEADING WHITESPACE, LEADING 0s, and Decimal */
while ( (isspace(Input[CounterForInput]) || Input[CounterForInput] == '0') && Input[CounterForInput] != 0 ) // Skip blanks and zeros
++CounterForInput;
if ( Input[CounterForInput] != '.' )
return *this; // Error, no decimal point
++CounterForInput; // Move to char after '.'
/* CHECK TO SEE IF POINTER IS POINTING AT AN ARRAY WITH ENOUGH ROOM FOR COPY */
Temp = CounterForInput;
while (isdigit(Input[Temp])) // get length of incoming float without affecting CounterForInput
{
++Length;
++Temp;
}
if (MaxNumberOfDigits<Length)
{
delete Number;
Number = new (nothrow) char[Length+1];
if (Number == NULL)
{
NumberOfDigits = 0;
return *this;
}
}
/* ASSIGN INPUT TO ARRAY BEING POINTED AT BY NUMBER */
while ( CounterForNumber <= MaxNumberOfDigits && isdigit(Input[CounterForInput]) ) // Copy rest of string
Number[CounterForNumber++] = Input[CounterForInput++] - '0';
NumberOfDigits = CounterForNumber;
while ( CounterForNumber < MaxNumberOfDigits ) // Pad with trailing zeros
Number[++CounterForNumber] = 0;
return *this;
}
/********************* operator=() ********************************
Action: Another Overloaded assignment operator to allow a MyFloat to be
copied to another MyFloat, by dynamically allocating memory for a new
array
Parameters:
IN: none
OUT: Const MyFloat &X
Returns: *this
Preconditions: none
*******************************************************************/
MyFloat MyFloat::operator= (const MyFloat &X)
{
if (MaxNumberOfDigits<X.MaxNumberOfDigits)
{
delete Number;
Number = new (nothrow) char [X.MaxNumberOfDigits+1];
if (Number == NULL)
{
NumberOfDigits=0;
return *this;
}
}
NumberOfDigits = X.NumberOfDigits;
MaxNumberOfDigits = X.MaxNumberOfDigits;
for (int i=0; i<=MaxNumberOfDigits; i++)
{
Number[i] = X.Number[i];
}
return *this;
}
/********************* operator==() ********************************
Action: Overloads the comparison operator to compare data members of
two different objects of MyFloat
Parameters:
IN: none
OUT: const MyFloat &x, which contains data members holding one float
Returns: 1 if both MyFloat numbers are equal, 0 if they are different
Preconditions: none
*******************************************************************/
int MyFloat::operator== (const MyFloat &x)
{
int Counter;
if (NumberOfDigits>x.NumberOfDigits)
Counter = NumberOfDigits;
else
Counter = x.NumberOfDigits;
for (int i=0; i<=Counter || Number[i]; ++i)
{
if (x.Number[i]!=Number[i])
return 0;
}
return 1;
}
/********************* operator+() ********************************
Action: Overloads the addition operator to allow it to add two MyFloats
together
Parameters:
IN: none
OUT: MyFloat x, which contains data members holding one float
Returns: MyFloat Storage back to main driver
Preconditions: none
*******************************************************************/
MyFloat MyFloat::operator+ (const MyFloat &X)
{
int Carry=0;
int Integer=0;
int DifferenceInLength=0;
int ForLoopCounter=0;
MyFloat Storage;
if (NumberOfDigits > X.NumberOfDigits)
{
Storage = *this;
//just copy larger float over to storage so it is large enough to hold new number
//new number will use the same ending numbers as the longest number as well
DifferenceInLength = NumberOfDigits - X.NumberOfDigits;
//Get the difference between the lengths of the two numbers, will be used in next for loop
ForLoopCounter=NumberOfDigits - DifferenceInLength;
}
else
{
Storage = X;
DifferenceInLength = X.NumberOfDigits - NumberOfDigits;
ForLoopCounter=X.NumberOfDigits - DifferenceInLength;
}
for (int i=ForLoopCounter-1; i>=0; --i) //- 1 to work with Array style counting
{
Integer = ((X.Number[i]) + (Number[i]) + (Carry));
Carry = 0;
if (Integer>=10)
{
Carry = Integer/10;
Integer %= 10;
}
Storage.Number[i] = Integer;
Integer = 0;
}
if (NumberOfDigits>X.NumberOfDigits)
Storage.NumberOfDigits = (NumberOfDigits);
else
Storage.NumberOfDigits = X.NumberOfDigits;//Storage.NumberOfDigits will be equal to the larger NumberOfDigits of the two floats being added
return Storage;
}
/********************* operator>() ********************************
Action: Overloads the greater than operator to allow two MyFloats to be
compared
Parameters:
IN: none
OUT: const MyFloat &x, which contains data members holding one float
Returns: 0 if false, 1 if true (if calling object is greater than object
being passed in)
Preconditions: none
*******************************************************************/
int MyFloat::operator> (const MyFloat &x)
{
for (int i=0; i<=MaxNumberOfDigits; ++i)
{
if (Number[i]<x.Number[i])
return 0;
else if (Number[i]>x.Number[i])
return 1;
}
return 1;
}
/********************* operator<<() ********************************
Action: Overloads << operator to allow it to work on custom MyFloat
data type
Parameters:
IN: none
OUT: ostream &Out, const MyFloat & x
Returns: Reference to ostream
Preconditions: none
*******************************************************************/
ostream & operator<< (ostream &Out, const MyFloat & X)
{
Out << "0.";
if (X.NumberOfDigits != 0)
{
for (int j=0; j<=X.NumberOfDigits-1; ++j)
{
Out << (int) X.Number[j];
}
}
else
Out << "?";
return Out;
}
/********************* operator>>() ********************************
Action: Reads and stores the float typed in by the user using certain
conditions. Skips all leading whitespace and 0s, then stores any
numbers after that.
Parameters:
IN: none
OUT: istream &In, Myfloat & x
Returns: reference to istream
Preconditions: none
*******************************************************************/
istream & operator>> (istream &In, MyFloat & X)
{
int Counter=0;
char Character;
cin.ignore(); // clear newline from input buffer, my algorithm doesn't
// work if newline is in input buffer when entering function
X.NumberOfDigits=0;
cin.get(Character);
while ((isspace(Character) || Character=='0') && (Character != '\n'))
cin.get(Character);
if (Character != '.')
return In;
cin.get(Character);
while (isdigit(Character) && Counter<=X.MaxNumberOfDigits-1)
{
X.Number[Counter]= Character-'0';
cin.get(Character);
++Counter;
}
cin.putback(Character);//puts back last character stored - newline in this case
X.NumberOfDigits= Counter;
for (; Counter<=X.MaxNumberOfDigits-1; ++Counter)
{
X.Number[Counter]=0;
}
cin.ignore(100, '\n'); // flush any extra numbers in input - mostly for when
// user types in a number longer than array can hold
return In;
}
答案 0 :(得分:2)
类C
的典型赋值运算符返回C&
- 对赋值左侧对象的引用。
相反,您可以按值返回该对象的副本。这是临时副本,然后立即销毁。