Can a class name be the name of an array? - c++

I get a "type name not found" problem when I try to use this array for my function.
class dancer {
public:
dancer();
void swap(int, int, dancer[]);
};
void dancer::swap(int num1, int num2, dancer[])
{
int current = dancer[num1];
dancer[num1] = dancer[num2];
dancer[num2] = current;
}
I'm supposed to use the class name as my array type for my assignment. I believe I made an error on setting up the array. The error is at int current = dancer[num1];
dancer[num1] = dancer[num2];
dancer[num2] = current;

void dancer::swap(int num1, int num2, dancer[])
Since dancer is a type this gets parsed as an anonymous method parameter that's an array of dancer objects, and not as some array, of some type named 'dancer'. You have to name this parameter:
void dancer::swap(int num1, int num2, dancer values[])
and then some values[num1] with values[num2].
However it is fairly likely that you have fundamentally misunderstood something about your programming assignment. It makes no logical sense to have a non-static class method that takes, as a parameter, an array of other instances of its own class, for this purpose.
You should reread your programming task's description. You are likely missing some part or detail of it; however the above is the explanation for your compilation error.

Related

How to create an iterator function

So my task is to create a function with signature: list<Person>::iterator SearchPos(list<Person> &Mylist, Person &person). Which would later get the appropraite position for the person, in order of birth, to be inserted into the list. Its return type should be an Iterator.
I have tried doing the following :
list<Person>::iterator SearchPos(list<Person> &MyList, Person &person)
{
}
int main()
{
char Dot;
string Dummy;
string Name;
int Day, Month, Year;
fstream MyFile;
MyFile.open("Kontakte.txt");
list<Person> BirthdayList; // Creating list of type Person
if(MyFile.is_open()) {cout << "File opened successfully." << endl;};
getline(MyFile, Name, ','); //Get line until "," is reached
MyFile >> Day >> Dot;
MyFile >> Month >> Dot;
MyFile >> Year;
getline(MyFile, Dummy); //Gets rid of \n char.
Person P1 (Name, Day, Month, Year);
SearchPos(&BirthdayList, &P1);
but even without the body of SearchPos() function I get the error :
invalid initialization of non-const reference of type 'std::__cxx11::list<Person>&' from an rvalue of type 'std::__cxx11::list<Person>*'|
Edit
Thanks a lot for the help with that error message it would take me embarrasingly long to figure that one out. The answer to my orginal question is as follows
list<Person>::iterator SearchPos(list<Person> &MyList, Person &person)
{
list<Person>::iterator pos;
//body of the function
return pos;
}
This will make the function return an iterator as wanted by my task.
After some getting used to, the compiler error is actually clear. Maybe this will help you to decipher it.
invalid initialization of non-const reference of type 'std::__cxx11::list&' from an rvalue of type 'std::__cxx11::list*'|
std::__cxx11::list<Person> is actually list<Person> in your code. The standard library just adds some namespaces. Maybe if we switch the example to int, it is clearer.
int SearchPos(int& index){} // let's define a function taking a reference to `int`.
int main() {
int my_index;
SearchPos(&my_index);
}
would similarly result in
invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int*'|
So the problem is that you cannot convert int* to int&.
Why? Well, they are different types, and you cannot convert between them.
Where is int* coming from? You are getting the type int*, since the operator & returns an address to the int, thus a pointer to int (int*). (extra, the returned address is a rvalue, since it itself does not have an address.)
So either you make sure that the type you are inputting corresponds to the signature of the method:
int SearchPos(int* index){}
int main() {
int my_index;
SearchPos(&my_index);
}
, or, what you should do, since the signature is set, you make sure you pass a reference:
int SearchPos(int& index){}
int main() {
int my_index;
SearchPos(my_index);
}
You need to call the function like this:
SearchPos(BirthdayList, P1);
As mentioned in the comments you were passing the parameters as pointers when your function was looking for a reference. Using the ampersand (&) returns a pointer to your object. I know it may be confusing and seem like you need to pass in the address since your function accepts a reference but you don't need to do that. Declaring it as a reference in the function parameters is all you need to do.

C++ Basic Class Constructor

I'm going through a C++ course right now, and they're doing a good job of over-explaining everything until it comes to splitting the files up between header "promises" and implementation. I learned programming entirely in Python so I'm used to just declaring things outright and importing the class as necessary, so this whole separating a promise and then implementing logic is strange to me.
Anyway, I'm having trouble because in the course they were saying you never actually need to use this-> but when I'm trying to define a class explicitly in the same .cpp file, I can only get the constructor to work when I use this->. Can someone please explain or link a discussion that explains this? I haven't been able to find a reference that explains this issue in the context of defining everything in the same file.
class Person {
public:
string name;
int age;
int height;
int weight;
Person (string name, int age, int height, int weight) {
name = name;
age = age;
height = height;
weight = weight;
}
};
int main () {
Person new_person("Doug", 20, 70, 170);
}
This causes all the values I pass in from the main function to not initialize. However, if I add this-> to each line in the constructor, it works fine. The examples I find don't use this-> so I'm confused why it's necessary here. Perhaps it has to do with namespaces which are still a little confusing to me (the whole using namespace std; thing) but I thought since it's all in the same .cpp file, this should work.
The argument variables overshadow your member variables in the scope of your constructor. That is, within that context, name refers to the input variable only.
What you could do is use an initialization list:
Person (string name, int age, int height, int weight) :
name(name), age(age), height(height), weight(weight) {}
Or use different names:
Person (string _name, int _age, int _height, int _weight) {
name = _name;
age = _age;
height = _height;
weight = _weight;
}
But your approach using this-> is totally fine.
You might also want to read http://www.cs.technion.ac.il/users/yechiel/c++-faq/using-this-in-ctors.html
In this case you need this because you are using the same name for both your constructor parameters and class members.
Person (string name, int age, int height, int weight) {
this->name = // this-> means the member variable
name; // just the parameter
If you had a different name for your parameter this would not be necessary
Person (string name_, int age, int height, int weight) {
name = // the member variable
name_; // the parameter
Only problem with ->this approach is that it is A) wordy b) doesn't initialize object. c) makes this object non-trivial.
Proper initializing constructor would look like this, using initialization list:
Person (string nm, int ag, int ht, int wt):
name(nm), age(ag), height(ht), weight(wt) {}
It's not really same as doing what you do, in this case object can be created statically without performing any actions. Your implementation of class always performs assignments. C++11 and later allows to do away with fully trivial implementation:
class Person {
public:
string name;
int age;
int height;
int weight;
void do_stuff() {};
};
// let's assume that string is std::string,
// creation from const char* and = are defined
int main()
{
Person p = { "Nemo", 35, 5, 120 };
Person p2 = p;
p = { "John-117", 24, 6, 170 };
}
What you have is a case of ambiguity of dependent names. See here:
If the lookup of a member of current instantiation gives a different
result between the point of instantiation and the point of definition,
the lookup is ambiguous. Note however that when a member name is used,
it is not automatically converted to a class member access expression,
only explicit member access expressions indicate members of current
instantiation:
Eli Bendersky writes eloquently about this. An excerpt:
All you have to do is to make the compiler understand that the call f depends on the template parameter T. A couple of ways to do this are replacing f() with Base::f(), or with this->f() (since this is implicitly dependent on T).
So your own this-> solution is more than fine : )

c++ class setter sets variables different when argumentname and variable name are equal

I'm completly new to c++ and I found something I don't understand and which I cannot find the answer for(also I'm sure it has been asked a lot, so point me to a thread would also be nice).
Example code:
#include <iostream>
class Car {
int doors;
public:
void set_doors(int doors){
doors = doors;
}
int get_doors(){
return doors;
}
};
int main()
{
Car ford;
ford.set_doors(3);
std::cout << ford.get_doors() << std::endl;
}
So when I run the code it returns always an int of length 9.
I know that the issue is happening because in
void set_doors(int doors)
I'm using the same name for the argument and the variable I'd like to change.
If I would change the code to
void set_doors(int newdoors){
doors = newdoors;
}
everything will work perfectly.
My question is:
Why does the code behave like this, when using the name for the variable which I like to modify and the argument name?
Please explain it in an easy way ;)
Thanks
Best
Why does the code behave like this, when using the name for the variable which I like to modify and the argument name?
Because the rules of C++ require it to behave this way: names of local variables and parameters "win" over member variables. You should get a compiler warning on this assignment, saying that the assignment has no effect (it assigns the value of a parameter back to itself).
One of idiomatic ways of resolving this is as follows:
this->doors = doors;
This is the way the language lets you resolve situations when an unqualified name could refer to more than one thing.
Your code has undefined behaviour, because you attempt to read an uninitialized variable. In the following function:
void set_doors(int doors){
doors = doors;
}
doors always refers to the function argument, not to the member variable. In other words, you self-assign the function argument and your doors member variable is left untouched. What's worse is the member variable is never initialized. Reading it in get_doors produces 9 only by sheer coincidence on your machine. The program could just do anything.
You can fix your setter function like this:
void set_doors(int doors){
this->doors = doors;
}
Still, your class would be very easy to use incorrectly, because it is not obvious that one should have to call set_doors before get_doors actually works. You want to initialize doors to 0 in the constructor:
class Car {
int doors;
public:
Car() : doors(0) {}
void set_doors(int doors){
this->doors = doors;
}
int get_doors(){
return doors;
}
};
Once inside the function get_doors, the argument 'doors' hides the member variable 'doors'. So the assignment 'doors = doors' basically assigns the function parameter doors to doors and the member variable is still left undefined.
Also, I would ideally not design the class this way, I would rather setup the class member variables in the constructor.
*
Class Car {
int doors; public:
Car(int doors): doors(doors) {}
int get_door_count(){ return doors; } };
*
Notice that in this case the compiler can correctly differentiate between the function argument doors and the member variable doors when using the member initialiser syntax.

Error: Conversion to non-scalar type

I am making a set of derived classes for an assignment. I am instructed to use char arrays (c-strings). When I compile I keep getting the error:
Homework11.cpp: In function âint main()â:
Homework11.cpp:72: error: conversion from âchar [10]â to non-scalar type âBusinessâ requested
Homework11.cpp:73: error: conversion from âchar [10]â to non-scalar type âBusinessâ requested
Homework11.cpp:74: error: conversion from âchar [10]â to non-scalar type âAccountâ requested
Homework11.cpp:75: error: conversion from âchar [10]â to non-scalar type âAccountâ requested
I am fairly certain that my problem is originating up where I try to set the instance variable Name to the argument sent in. Here is my code with comments in where I believe the problems may be.
#include <iomanip>
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
class Person{
public:
Person() {}
Person(char theName[]) {strcpy(name,theName);}
void getName(char theName[]) // I think the problem may be here or in the line above
{ theName = name;}
private:
char name[80];
};
class Account : public Person{
public:
Account() :accountNum(0),balance(0) {}
Account(int actNo, char theName[])
:Person(theName),accountNum(actNo),balance(0) {}
void setBal(float theBalance)
{balance = theBalance;}
void deposit(float numDeposited)
{ balance = balance + numDeposited;}
float withdraw(float numWithdrawn)
{ balance = balance -numWithdrawn;
return numWithdrawn;}
float getBal() {return balance;}
void printBal();
private:
int accountNum;
float balance;
};
class Business : public Account{
public:
Business() : checkFee(0.0) {}
Business(int actNo, char theName[])
: Account(actNo, theName),checkFee(0.0) {}
float withdraw(float numWithdrawn)
{float newBalance = getBal()-numWithdrawn-checkFee;
setBal(newBalance);
return numWithdrawn;}
void setFee(float fee) {checkFee = fee;}
private:
float checkFee;
};
void Account::printBal()
{
char name[80];
getName(name);
cout<<setw(10)<<"Account # "<<accountNum<<setw(10)<<
name<<setw(10)<<balance<<endl;
}
int main()
{
char businessName1[10]="Business1";
char businessName2[10] ="Business2";
char regularName1[10] = "Regular1";
char regularName2[10] = "Regular2";
//The following 4 lines are the ones I am getting the error for
Business bs1 = (1,businessName1);
Business bs2 = (2,businessName2);
Account rg1 = (1, regularName1);
Account rg2 = (2, regularName2);
cout<<"Intially: "<<endl;
rg1.printBal();
rg2.printBal();
bs1.printBal();
bs2.printBal();
bs1.deposit(1000.00);
bs2.deposit(1000.00);
rg1.deposit(1000.00);
rg2.deposit(1000.00);
cout<<"----------------------------------------"<<endl;
cout<<"After adding 1000.00 to all accounts:"<<endl;
rg1.printBal();
rg2.printBal();
bs1.printBal();
bs2.printBal();
bs1.setFee(1.00);
bs1.withdraw(500);
bs2.withdraw(500);
bs1.deposit(250);
bs2.deposit(250);
rg1.withdraw(500);
rg2.deposit(500);
cout<<"---------------------------------------"<<endl;
cout<<"Finially:"<<endl;
rg1.printBal();
rg2.printBal();
bs1.printBal();
bs2.printBal();
return 0;
}
The proper syntax would be Business bs1(1,businessName1);. If you want to use =, you can also use copy intialization Business bs2 = Business(2,businessName2);.
The former is known as direct initialization. They aren't exactly the same thing though, see Is there a difference in C++ between copy initialization and direct initialization? for in-depth information.
In Business bs1 = (1,businessName1); the 1 and array businessName1 are separated by the comma operator. The comma operator evaluates the first operand, i.e. 1 and throws away the results and returns the value of the second operand, which is an array in your case. In other words, your code is the equivalent of Business bs1 = businessName1;. This is why the error message says it cannot convert a char[10] to a Business object.
Change the first line that produces an error to Business bs1(1,businessName1); and the rest similarly. That's the C++ idiom for initialization of a class instance on the stack.
Business bs2 = Business(2,businessName2); as suggested by Jesse Good is, I'd argue, a Java idiom that is poor practice in C++. It's slower because there are two implicit constructor calls and one copy constructor call, as opposed to the single constructor call in Business bs1(1,businessName1);. In this case there is another trap: you have not defined a copy constructor for the Business type, which means that the compiler will create one for you that does a shallow copy. bs2.name will end up a pointer to memory that isn't necessarily correctly freed when bs2 goes out of scope--a classic memory leak.
The corresponding C++ idiom is instead to construct a new object on the heap, then assign its address to a pointer: Business *bs2 = new Business(2,businessName2);.
There's another problem with your code. Generally, it's also bad style to assign arrays by name in C or C++ (and remember, statically allocated strings like char theName[] are just a special kind of array). Look at the definition of getName() in Person:
void getName(char theName[])
{ theName = name; }
This is assigning the array names (which are not exactly pointers, but close cousins), not copying the contents of one string to another. In printBal() you then write
char name[80];
getName(name);
When getName() executes it binds printBal()'s local variable name to the parameter theName. So far, so good, although the variable names you choose could be a little less confusing. :) But then the body of getName() executes and assigns the address of the private instance variable name to theName (which is the name of an array--again, a special kind of pointer). When getName() returns, there's no permanent change to the local variable name in printBal(). The correct way to write Person::getName() would be with strcpy(), the way you wrote the second Person constructor:
void getName(char theName[])
{ strcpy(theName,name); }

Accessing a 2D array between two friend classes

My question is how to access and modify a 2D array defined in one class that is friends with another class. Below are some details on my question:
In class A I declare and allocate the appropriate space for my 2D array (pointer-to-pointer) u.
Class A
{
public:
friend class B;
long double **u;
int fun;
void make();
};
void A::make()
{
long double **u = new long double *[nx];
for (int i=0;i<nx;i++)
u[i] = new long double [ny];
int fun = 9;
}
Class A is friends with Class B; I need to use the array I declared in Class A in a function defined in class B. Below is my Class B:
class B
{
public:
void get(A*);
};
void B::get(A *pt)
{
using namespace std;
cout << pt->fun;
cout << pt->u[0][0];
}
I get a Bus error on my second cout pt->u[0][0]. Is there a simple way to use this setup I have to access my u[][] array? I think that I get the error because the pointer points to the 1st entry of my array, thus my whole 2D array is saved in memory as a single row (thinking aloud here). I'm a Fortran guy so this stuff is a little new to me.
Any help or "pointers" to other helpful threads would be appreciated.
Thank you !
Alberto
I think you get error because A::u is not initialized ( in method A::make you initialize a local variable u, not member. You need to change
void A::make()
{
long double **u = new long double *[nx]; // should be just u, or this->u.
There are some problems with your code: nx and ny don't seem to be defined anywhere, and in make you don't initialize A::fun at all, you instead set a local variable named fun which goes out of scope immediately.
As for your error, it sounds like the error stems from the fact that make() has not been called on pt. Ensure that make() is called on the instance you pass to get, otherwise the array u will not be allocated.