I implemented a class named bignumber that takes a big number as a string and stores it in an array.
I made a friend operation + for it to add two bignumbers. After running I get an error that the program doesn't respond. What is the problem?
.h file:
class bignumber
{
private:
int *number;
int size;
string num;
public:
bignumber(int);
bignumber(string ,int);
~bignumber();
friend bignumber operator+(bignumber,bignumber);
};
definitions:
bignumber :: bignumber(int numsize)
{
this->size= numsize;
this->number= new int[size];
};
bignumber :: bignumber(string inputnum,int numsize)
{
int *number = new int[numsize];
size = numsize;
num = inputnum;
for(int i=0;i<numsize;i++){
number[i] = int(num[i])-48;
};
};
bignumber :: ~bignumber()
{
delete [] number;
};
bignumber operator+(bignumber num1,bignumber num2)
{
if(num2.size>num1.size){
int e = num2.size - num1.size - 1;
int *tempnum = new int [num2.size];
for(int i=0;i<num1.size;i++){
tempnum[e+i] = num1.number[i];
}
delete [] num1.number;
num1.number = new int[num2.size];
for(int i=0;i<num2.size;i++){
num1.number[i] = tempnum[i];
}
delete [] tempnum;
}
else if(num1.size>num2.size){
int e = num1.size - num2.size - 1;
int *tempnum = new int [num1.size];
for(int i=0;i<num2.size;i++){
tempnum[e+i] = num2.number[i];
}
delete [] num2.number;
num2.number = new int[num1.size];
for(int i=0;i<num1.size;i++){
num2.number[i] = tempnum[i];
}
delete [] tempnum;
}
bignumber temp(max(num1.size,num2.size));
int carry = 0;
for(int i = 0;i < temp.size;i++){
temp.number[i] = num1.number[i] + num2.number[i] + carry;
if (temp.number[i] > 10){
temp.number[i] -= 10;
int carry = 1;
}
};
if(carry = 1){
int *temp2 = new int[temp.size+1];
temp2[0] = carry;
for(int j = 1;j < temp.size+1;j++){
temp2[j] = temp.number[j-1];
};
temp.size += 1;
delete [] temp.number;
temp.number = new int[temp.size];
for(int i=0;i<temp.size;i++){
temp.number[i] = temp2[i];
}
delete [] temp2;
};
};
Also I don't know how to define operator >> to input the number. I wrote this as a friend but it doesn't work:
istream& operator>>(string s,int size)
{
bignumber(s,size);
};
1) You haven't provided the copy constructor, so compiler makes the copy constructor with shallow copy. The same goes for operator=. That's very wrong when you manually allocate memory.
Call to operator+ where you pass parameters by value will result in creating two shallow temporary copies of operands. Then you modify these temporaries deleting the pointers and setting them to new values. But operands know nothing about it, their number pointers will still point to deleted memory, so the operands will become unusable and crash your program on any access to them or on destruction (when their destructors will try to delete the already deleted).
You do not return anything in your operator+, but you have to, and there the lack of copy constructor will result in another allocation error.
2) To pass complex objects by value is rarely a good practice, do it only if you have real reasons. Otherwise, use const myclass& param instead. For your operator+, the signature would be bignumber operator+(const bignumber& num1, const bignumber& num2). Yes, since you cannot modify num1 and num2, you will still need a local copy of the number that needs to grow, but this is one copying instead of two that you've got.
3) implementing operator+ is best done when you've already implemented more simple MyClass& MyClass::operator+=(const MyClass& that); After that, you can use
MyClass operator+(const MyClass& first, const MyClass& second)
{
MyClass retval(first);
retval+=second;
return retval;
}
Your operator+ will still be more complex than needed because you haven't provided some essential functions. You resize your number several times -- why don't you make it a member function resize(int newsize)? You could test and debug it separately, then your operators will be much simpler.
...which all leads to an obvious question: why don't you use vector<int> number? It will solve all the problems above: the compiler-generated constructors and operator= will work fine, no allocation nightmares, resize() and lots of other useful functions are already provided and thoroughly tested. Or, you can use string only: ints are actually wasted in your code, since you store only numbers 0..9 in each of them. Define member functions like int2character and character2int, and you've got rid of most of your problems.
4) operator>> for streams should have a signature
istream& operator>>(istream& is, bignumber& num);
and be something like that:
istream& operator>>(istream& is, bignumber& num)
{
string strTmp;
is>>strTmp;
//checks for istream state etc
//...
//calculate size of number from the extracted string
//...
//then construct a temporary
bignumber tmp(strTmp, calcsize);
num=tmp;//don't forget assignment operator
//or
//just provide a method to reset value of bignumber from string
//it can be a member function
num.assign(strTmp);
//or operator=(const string& str);
num=strTmp;
return is;
}
That is, usually to make your stream operator, you use already defined stream operators for other types.
5) you do not reset carry flag in cycle after you've used it.
Related
for homework, I need to write a program in cpp with a class composed of an array of pointer to function and operators. I need to create an operator + so as when in the main, this would happen:
int main()
{
int SIZE = 5;
ptrF* arrPtrF = new ptrF[SIZE];
arrPtrF[0] = add;
arrPtrF[1] = sub;
arrPtrF[2] = mult;
arrPtrF[3] = div1;
arrPtrF[4] = pow;
Delegate D1(arrPtrF, SIZE)
cout<< D1[0](6, 7) + D1[0](1, 2)<<endl;
}
the outcome is 15
I am finding difficulty with writing the operator+ ( which in this case need to take take a object parameter)
at first i tried this:
Delegate Delegate:: operator + (const Delegate& b)
{
Delegate tmp;
tmp.m_ptrF[i] = m_ptrF[i] + b.m_ptrF[i];
return tmp;
}
but it gave me an error about the i and b.m_ptrF->initialized i and something about an enum type.
then i tried this:
int Delegate:: operator + (const Delegate& b)
{
int tmp;
int i, x,y;
tmp = m_ptrF[i](x, y) + b.m_ptrF[i](x, y);
return tmp;
}
but it gives me an error->initialized x,y,i knowing that i is index and x,y the parameters of the pointer to function.
what can i do to make it work?
It looks like D1[0](6, 7) is supposed to perform 6 + 7 returning an int and D1[0](1, 2) is supposed to perform 1 + 2 also returning an int. So the addition in D1[0](6, 7) + D1[0](1, 2) is just a regular int addition.
So in other words you are not supposed to be overloading Delegate::operator+ instead you are supposed to writing something like this
XXX Delegate::operator[](int i) const
{
...
}
where XXX is a function like type that will perform the addition on the later parameters.
So XXX will be something like
class XXX
{
public:
int operator()(int x, int y) const
{
...
}
...
};
But XXX will have to perform addition, or substraction or whatever, as appropriate.
So the expression D1[0](6, 7) becomes temp(6,7) where temp is an object of the XXX type above.
At least that's my best interpretation. It's clear that you have misunderstood your requirements.
I cannot figure out how to sort a vector of objects by one of the member variables called VIN, which is of data type string. I am to either perform a bubble sort or a selection sort. I am most familiar with a bubble sort, so that's the direction I attempted to take. However, I am aware that I need to compare both of the strings by either making them all uppercase or lower case. Keep in mind, the strings also will have number characters in them as well.
So my question is:
1) How to I convert a string either all lowercase or all ASCII numbers and
2) What data type should the temp variable be (data type of the class or some other data type).
Here is the (incomplete) code I have so far:
void sortInventory(vector<Vehicle> &carList)
{
bool swap;
string temp;
do
{
swap = false;
for (int count = 0; count < carList.size(); count++)
{
if (carList[count].getVIN() > carList[count + 1].getVIN())
{
temp = carList[count].getVIN();
carList[count].getVIN() = carList[count + 1].getVIN();
carList[count + 1].getVIN() = temp;
swap = true;
}
}
} while (swap);
}
Here is my class declaration:
class Vehicle
{
private:
string VIN;
public:
string getVIN();
void setVIN(string);
};
Here is my class implementation:
string Vehicle::getVIN()
{ return VIN; }
void Vehicle::setVIN(string input)
{ VIN = input; }
Thanks!
You can do std::sort(carList.begin(),carList.end(),vehicleCompare) where vehicleCompare is a comparison function that you define. See sort documentation. Then, to uppercase you can use std::toupper, as shown in this guide.
std::string myToUpper(std::string in) {
std::transform(in.begin(), in.end(),in.begin(), ::toupper);
return in;
}
So the comparison operator(*) will be:
bool vehicleCompare (const Vehicle a, const Vehicle b) {
const std::string a_name = myToUpper(a.getVIN());
const std::string b_name = myToupper(b.getVIN());
return (a_name < b_name);
}
Useful reading about string comparison operator.
By the way, your string getVIN() method should be const, that is you should change its declaration to string getVIN() const.
If you want to keep your sorting function, the point is that in any case you'll have to define a proper comparison operator, as the one shown here.
To specifically answer to your second question, temp could be auto in C++11, or simply std::string. Then the way you are trying to assign your VIN value is wrong. Given the interface you have given, it should be:
auto temp = carList[count].getVIN();
carList[count].setVIN(carList[count + 1].getVIN() );
carList[count + 1].setVIN(temp);
Although it still might get nasty when you start to have more than one member variable to copy: you should instead build a copy constructor and change your code to:
auto temp = carList[count]; //you can use Vehicle instead of auto as type
carList[count] = carList[count + 1];
carList[count + 1] = temp;
The copy constructor will be:
Vehicle(const Vehicle& in)
: VIN(in.getVIN() )
{}
And, at that point, you'll also want a constructor from string, and an empty constructor.
Vehicle(std::string& inVIN)
: VIN(inVIN)
{}
Vehicle(const Vehicle& in)
{} //All input members get initialized through the default constructor.
(*) Note that this comparison method wouldn't be the most efficient, as it makes uppercase the whole string while the first few characters are normally sufficient to decide their order. So a more efficient way would be to uppercase one character at the time and compare it before deciding if to uppercase another character.
Answer to question 1: You can make a simple function that converts a std::string to upper.
void string_to_upper(string &s) {
for(int l = 0; l < s.length(); ++l) {
s[l] = toupper(s[l]);
}
}
First, your Vehicle::getVIN() method should be marked as const, to implement proper const-correctness:
string Vehicle::getVIN() const
{
return VIN;
}
Then, note that you don't need to reinvent the wheel and reimplement a sorting algorithm from scratch in production code in C++ (unless this is a learning exercise/homework about writing sorting code).
You can simply use the standard std::sort() algorithm implemented in the STL, and customize the comparison criteria using a convenient C++11 lambda, e.g.:
// std::vector<Vehicle> carList;
std::sort(carList.begin(), carList.end(),
[](const Vehicle& v1, const Vehicle& s2)
{
/* Code implementing custom Vehicle comparison */
}
);
Your code in the lambda could be something like this:
[](const Vehicle& v1, const Vehicle& s2)
{
// Use stricmp() to compare strings in a case insensitive way
return (stricmp(v1.getVIN().c_str(), v2.getVIN().c_str()) < 0);
}
Instead of calling stricmp(), you can use boost::to_upper(), or some other method among the ones showed e.g. in this thread on StackOverflow:
Case insensitive string comparison in C++
I'm working on operator overloading for a self made dynamic array class. I'm also trying to learn how to use the *this pointer but it's not going so well. Below are the parts of the class and my code that I thought were needed to explain the issue.
I don't understand why I can't call a member function on the *this pointer when the *this pointer is pointing to the left side of the + equation.
Here is the stub driver that is calling the + operator:
<< and >> are already overloaded and working.
cout << "Please enter a word to add:";
string theWord;
cin >> theWord;
//add word
array1 = array1 + theWord;
cout << "array1: " << array1 << endl;
Here is the main code:
class DynamicArray
{
public:
//constructor
DynamicArray(int initialcapacity = 10);
//copy constructor
DynamicArray(const DynamicArray& rhs);
//destructor
~DynamicArray();
//operator+ - add a string
DynamicArray operator+(const string& rhs) const;
//operator+ - concatenate another DynamicArray
DynamicArray operator+(const DynamicArray& rhs) const;
//change the capacity of the DynamicArray to the newCapacity -
// may reduce the size of the array - entries past newCapacity will be lost
void resize(int newCapacity);
private:
string* mWords;//pointer to dynamic array of strings
int mNumWords;//the current number of words being kept in the dynamic array
int mCapacity;//the current capacity of the dynamic array (how many strings could fit in the array)
//display all the contained strings (each on a newline) to the output stream provided
void displayContents(ostream& output) const;
//add all the strings contained in the input stream to the dynamic array - resize if necessary
//return how many words are added to the array
int addWords(ifstream &input);
//add a single word to the dynamic array - resize if necessary
void addWord(const string& word);
};
//add a single word to the dynamic array - resize if necessary
void DynamicArray::addWord(const string& word)
{
if (mNumWords >= mCapacity)//need more space?
{
resize(mCapacity + 1);
}
mWords[mNumWords] = word;
mNumWords++;
}
This is the function I'm currently working on
//operator+ - add a string
DynamicArray DynamicArray::operator+(const string& rhs) const
{
//this doesn't work, why doesn't it, how should/do I use the
//this pointer properly
this.addWord(rhs);
return *this;
}
In addition to using this. instead of this->, you have defined operator+ as a const member function. This means that no members can be mutated, and no calls to non-const member function functions are to be performed. Your addword function is non-const. That's the reason for the error -- you are violating const correctness.
Also, why are you mutating the array for merely calling operator + in your code? That operator shouldn't need to change any aspect of the current object. I can understand operator += mutating the object, but not operator +.
What you should do is write an operator += first. This operator can mutate the current object, since that is the semantics of += (change the current object). Then operator + can be written this way:
//operator+ - add a string
DynamicArray DynamicArray::operator+(const string& rhs) const
{
DynamicArray temp = *this;
temp += rhs;
return temp;
}
This is assuming you have a working copy constructor. In the example above, you are mutating a temporary, calling += on the temporary, and returning the temporary. The this object does not change.
Here is what your operator += should look like:
DynamicArray& DynamicArray::operator+=(const string& rhs)
{
this.addWord(rhs);
return *this;
}
Now operator += becomes non-const because the intention of += is to change the current object. Note that the return value is a reference to the current object. This now works in concert with the operator + above.
Your operator+ has to be non-const since you want to change the state of the object on each it is invoked. Also you don't have to write
this->addWord( rhs); // correct but not needed
because use of method inside a class member function is called on this pointer implicitly. Given this, you may write:
DynamicArray DynamicArray::operator+(const string& rhs)
{
addWord( rhs);
return *this;
}
You can also implement this operator as void:
void DynamicArray::operator+(const string& rhs)
{
addWord( rhs);
}
and use it this way:
array1 + theWord;
Hi I have a test tomarrow and can't figure out why subtraction is made on the pointer before checking if the refcount is 0. I've been searching on google but still cant figure it out. So I'm hoping turning to you guys :) would help.
Easyiest is too just show you the code, I've marked the lines with comments, so here it is:
This is the class StringRep that has pointers to it for counting pointerref to it,
struct StringRep{
int size; // amount of chars incl. EOL \0-tecken
char* chars; // Pointer to char
int refCount; // Amount of String-variables
};
And this is class String that uses the StringRep,
class String{
public:
String(char* str);
String(const String& other);
~String();
const String& operator=(const String& rhs);
char get(int index) const { return srep->chars[index]; }
void put(char ch, int index);
private:
StringRep* srep;
};
String::String(const String& other):srep(other.srep){
srep->refCount++;
}
String::~String(){
if (--srep->refCount == 0){ //why --srep here?
delete [] srep->chars;
delete srep;
}
}
const String& String::operator=(const String& rhs){
if (srep != rhs.srep){
if (--srep->refCount == 0){ //why --srep here?
delete [] srep->chars;
delete srep;
}
srep = rhs.srep;
srep->refCount++;
}
return *this;
}
void String::put(char ch, int index){
if (srep->refCount > 1){ //Why not --srep here?
StringRep* tmpRep = new StringRep;
tmpRep->refCount = 1;
tmpRep->size = srep->size;
tmpRep->chars = new char[tmpRep->size];
std::strcpy(tmpRep->chars, srep->chars);
--srep->refCount;
srep = tmpRep;
}
srep->chars[index] = ch;
}
This is all info I have on the example question for the test, I know that --spek points to the object before spek, but cant figure out the logic behing checking if what is pointed at before now is 0 then its okey to delete, or to copy, but why? As I said I've searched the webb and have found some answers to help me understand the functions of the pointer and the subtraction etc, it more the logic that is confusing.
Best regards
Because of operator precendence, --srep->refCount is not decrementing srep, but the refCount member.
So, the code is decrementing the refCount, and if it comes down to 0, it can assume that the last reference to the object is being destroyed.
--srep->refCount
is parsed as
--(srep->refCount)
because prefix decrement has lower priority than -> (however, postfix decrement has the same priority as ->). Always use parens in your own code!
So, I'm new to C++ (brand new), and as an assignment I have to write a class that acts as an array wrapper. Since I'm so new, I'm unsure whether my overloaded operators and such work, so if anyone could be so kind as to tell me how my code looks:
This would be the header:
class MyArray
{
private:
string* sList;
unsigned int size;
public:
MyArray(const unsigned int size = 1);
MyArray(const MyArray &toCopy);
MyArray& operator=(const MyArray& toAssign);
~MyArray();
//MyArray& operator+
string& operator[](const int index);
const int size();
};
And this would be the underlying code:
MyArray::MyArray(const unsigned int initSize)
: size(initSize)
{
sList = new string[initSize];
return;
}
MyArray::MyArray(const MyArray &toCopy)
: size(toCopy.size)
{
if(toCopy.sList)
{
sList = new string[size];
for(int a=0; a<size; a++){
strcpy(sList[a], toCopy.sList[a]);
}
}
else sList = NULL;
return;
}
MyArray& operator=(const MyArray& toAssign)
{
if(this != &toAssign)
{
if(sList)
{
delete [] sList;
}
size = toAssign.size;
if (toAssign.sList)
{
sList = new string[size];
for(int a=0; a<size; a++){
strcpy(sList[a], toCopy.sList[a]);
}
}
else
{
sList = NULL
}
}
}
MyArray::~MyArray()
{
delete [] sList;
return;
}
string& MyArray::operator[](const int index)
{
return sList[index];
}
const int MyArray::size()
{
return this.size;
}
The operator+ function still needs to be written, but I want to make sure what I have makes sense before I proceed.
How do you want your code (i.e. the class you are authoring) to be used by other programmers (including you)?
Write an example program to demonstrate the use of your class.
An example program serves as a rudimentary test set. You can start as the following.
int main() {
MyArray arr1( 5 );
MyArray arr2( arr1 );
}
Have you thought about how user code will put (string?) elements into the MyArray class?
There are couple of other issues with the current version of the code. That is okay to begin with, but it is important for you to learn to test your own code; you need to learn the skill where you have some basic confidence in your own code (not necessarily perfect code) because you cannot always ask somebody else to test your code.
Suggestion: Since you mentioned that you are new, I would suggest you to build a array wrapper class for int's first. This is because, managing strings has some extra challenges than managing ints :-). Once you do that, you can easily do it for strings.
There is a naming conflict between size and size()
Copy C++ strings using =, not strcpy (which is for char*)
Missing MyArray:: in definition of operator=
toCopy should be toAssign in operator=
Missing semicolon after sList = NULL
Missing return *this; at the end of operator=
In defintion of size(), this.size should be size, this->size or (*this).size
All of these mistakes will be discovered by a compiler (you may need to enable warnings for the missing return to be reported; on g++ use the -Wall flag). It is just a matter of understanding the compiler's error messages and knowing how to fix the problems.