I have this constructor
Movie::Movie(char *&t, char *&d)
{
title = t;
director = d;
}
And in my main I have this:
Movie * movies = new Movie[movie_size];//creating array of class "Movie"
Movie *movieone=new Movie("MovieTitle", "Director");
movies[0]=movieone;
I get the following error:
no matching constructor for initialization of 'Movie' main.cpp line 14 C/C++ Problem
Isn't this correct, am I missing something? Thanks
When you do this
Movie("MovieTitle", "Director");
you are passing string literals, which collapse to const char*. But your constructor takes non-const references to char *:
Movie::Movie(char *&t, char *&d) { .... }
You cannot bind non-const references to something that is const. But in actual fact, it doesn't look like you need references at all. Just take the pointers by value, but make them point to somewhing const:
Movie::Movie(const char* t, const char* d)
This requires that you change title and director to const char*, which makes sense if you want to make them point to string literals.
But note that the design relies on the caller passing string literals, or passing pointers to objects that will outlive the given Movie instance. This can be made to work, but is quite fragile. The safer option would be for the Movie to "own" the data, which can easily be done by giving it std::string member variables.
As juanchopanza noted, the problem is that string literals get converted to type const char*, but your constructor only takes references to (non-const) char*, so it doesn't match.
A second point is that
Movie * movies = new Movie[movie_size];//creating array of class "Movie"
Movie *movieone=new Movie("MovieTitle", "Director");
movies[0]=movieone;
won't work. The first line creates an array of Movies (or tries to -- it won't work unless you have a default constructor), but the third line tries to set the first entry to a Movie*. Instead, you need to either a) create movies as an array holding pointers to Movies, or b) copy movieone by saying
movies[0] = *movieone;
Either way, you need to be very careful with regard to object lifetimes with this approach; it would be very easy to either leak memory on the one hand, or keep references to non-existent objects on the other.
A much better approach is to not (directly) use any dynamic memory allocation at all. You can use standard library facilities which hide it all for you, like this:
class Movie
{
public:
Movie(const std::string& title, const std::string& director)
: _title(title), _director(director) {}
private:
std::string _title;
std::string _director;
};
// later...
std::vector<Movie> movies;
movies.push_back(Movie("Jurassic Park", "Steven Speilberg"));
This is safer, easier to use, and no less efficient than your approach above.
Consider using std::string for store strings in class. For arguments pass better use const string& or const char*.
Movie *movieone=new Movie("MovieTitle", "Director");
Here you're passing const char*, but your constructor expects char*, so it doesn't match. Consider changing constructor to string or const char*
Related
I need some help.
this is my function:
class teacher
{
public:
char &operator[](int i);
protected:
char* contents;
};
.cpp
char & teacher::operator[](int i)
{
return contents[i];
}
main
teacher s1;
cout<<"Enter names: "<<endl;
cin>>s1[1];
cout<<s1[1];
If I enter a word, it only returns the first character, I don't know why if I'm using a char*
If you want an array of char* you need to make it a char**. contents[i] is a char, not a char*.
Why not use a vector<string> ?
You use a char*, but your operator [] returns a char&, which is not the same as a char*.
If you modify the char& you modify only one character.
What you want to be doing is this:
class teacher {
public:
char*& operator[](int i);
protected:
char** contents;
};
char*& teacher::operator[](int i) {
return contents[i];
}
Here you have an array of char*, i. e. C-style strings. The [] operator returns one of these char* as a reference, so that the code can change the pointer to point to some other string. This is according to the common C++ accessor idiom.
If you would choose to use std::string, you would just need to replace all occurences of char* with std::string.
Personally, however, I don't say that this approach is necessarily the best one; I have some objections against interfaces that expose the inner workings of a class like this. In this case any caller can obtain a reference to a pointer used by the class, and can use it at any later time to directly modify the contents of teacher without going through another teacher method. This makes it impossible to ensure any consistency of contents with the value of any other data member of teacher.
I try to avoid accessors in code I write, and favour methods that actually do something. That helps avoid code clutter and allows method names to name higher level operations. But that is just my opinion, many other people see it very differently.
i dont really get the fields of the template std::vector, the first one specifies the type, for example a class, but i dont get the allocator, pointer and reference variables.
i will provide a simple example, i want to use a vector of class person, so i have to say to the template vector: hey, store me some person's, but i also have to tell the vector how to allocate that class. (1)How would a correct syntax be for that example?
some code to start with:
side note, in the person's constructor,c(2)should i use date*?
class date
{
public:
int m_nMonth;
int m_nDay;
int m_nYear;
int getMonth(return m_nMonth;)
int getDay(return m_nDay;)
int getYear(return m_nYear;)
void setDate(int month, int day, int year)
{
m_nMonth=month;
m_nDay=day;
m_nYear=year;
}
date()
{
setDate(0,0,0);
}
date(int month, int day, int year)
{
setDate(month,day,year);
}
void printDate()
{
printf("%d/%d/%d", m_nMonth, m_nDay, m_nYear);
}
}
class person
{
public:
int m_nID;
char m_sName[128];
char m_sSurname[128];
date m_cBirthDay;
void setName(const char* name)
{
strncpy(m_sName, name, 127);
m_sName[127]= '\0';
}
void setSurname(const char* surname)
{
strncpy(m_sSurname, surname, 127);
m_sName[127]= '\0';
}
void setBirthDay(date* bday);
{
m_cBirthDay.date(bday.getMonth(), bday.getDay(), bday.getYear)
}
person(int id, const char* name, const char* surname, date bday)/*should it be date* bday? why?*/
{
m_nID=id;
setName(name);
setSurname(surname);
setBirthDay(bday);
}
}
i suppose you have to declare a function inside class person, called allocator, that is whats passed as second argument when you call, (3)how would that allocator function be defined?:
vector <person*, /*some allocator call*/> ImAVector;
then, (4)how could i push something in the vector, (5)would this work?:
person* someperson;
someperson.person(/*arguments*/);
ImAVector.push_back(someperson);
(6)how could i retrieve the pointer to a particular instance? (7)can i use the iterator to do something like this?:
//(6)
person* = ImAVector[someIterator];
//and then (7)
ImAVector[someIterator].setName(someConstCharPointer);
string* something = person.getName();
also, (8)does the allocator have anything to do with the constructor? (9)its common procedure to fill your class's fields right after allocating the instance of the class? (10)can an allocator call a constructor?
And the last questions: (11)what is the reference field, the pointer field, and their const counterparts?
I know its a lot to write, but ive spent the last two days searching for examples without success, so it would be nice if someone shed some light into this rarely discussed topic, ive numerated all questions for an easy response.
I appreciate any answers :)
How would a correct syntax be for that example?
Unless you have a good reason for storing pointers, don't. Then you just declare
std::vector<person> people;
// In C++11, you can create people in place
people.emplace_back(id, name, surname, birthday);
// Historically, you had to create a person and copy it in
people.push_back(person(id, name, surname, birthday));
and all the allocation is managed for you.
Reasons for wanting pointers include:
the vector is not supposed to manage the objects. In that case, you don't need to tell the vector how to allocate them.
perhaps person is a base class and you want to store various different subtypes.
In that case, I don't think you can use an allocator to help; instead, you could store smart pointers to automatically delete the objects when the pointer is removed from the container:
std::vector<std::unique_ptr<person>> people;
people.push_back(std::unique_ptr<person>(new person(id, name, surname, birthday)));
The alternative is to juggle raw pointers and try to delete the objects at the right time; but life's too short for that nonsense.
(2)should i use date*?
No. For a large or complicated class, it might be beneficial to pass a const reference, const date&; but this class is simple enough to pass by value. Passing a pointer would be weird, except in languages like C where that's the only way to pass by reference.
how could i retrieve the pointer to a particular instance?
people[index] gives a reference (not pointer) to the person with that index. If you really want a pointer for some reason, use & to take the address:
person & ref = people[index];
person * ptr = &ref;
can i use the iterator to do something like this?
No, [] is used to access by the array index, not to dereference an iterator. If you have an iterator it, then *it gives you a reference to the object.
does the allocator have anything to do with the constructor?
No, allocators are used if you have special memory-management requirements, and don't want the vector to simply allocate memory on the heap. There use is quite rare.
its common procedure to fill your class's fields right after allocating the instance of the class
It's common to initialise all the data members in the constructor, yes.
You don't need to specify anything other than the type.
vector<person> people;
people.emplace_back(/* constructor arguments for a person */); // constructs the person in place instead of copying into the vector.
person p;
p.stuff();
vector.push_back(p); // copies p into the vector
etc. Basically the defaults for allocator and the other fields are good enough, no need to specify them unless you have reason to override the default behavior. I've never had reason to do so.
I have a class which basically is a text manager. It can draw text and whatnot. I basically want the color and text std::string to only be a constant reference. Would it then be alright to do
class TextManager {
const std::string &text;
void draw(const std::string &text) const;
public:
TextManager(const std::string &text)
{
this->text = text;
}
void someMethod()
{
draw(text);
}
};
I want when the class that owns an instance of TextManager's text changes, the change is reflected in the TextManager.
would I be better off using a pointer?
thanks
If you never need to re-seat the reference (i.e. refer to a different object), then it's fine. But in my experience, you'll inevitably find out later down the line that you need to be more flexible, in which case a reference is a pain. It may be better to go with a pointer from the start.
But note that you can only initialise a member variable of reference type in the constructor initialiser list. (Also, you probably want to declare that constructor as explicit).
This code doesn't compile. this->text = text doesn't do what you think it does - it's not like Java where assigning a reference is like changing the pointer. reference = value will actually invoke the copy operator, so it will copy the value of the rhs to the lhs, either as member-by-member copy or using the operator= if it was overridden. Since your text is const, you can't do that.
So in this case, you have to use a pointer - references cannot be modified once initialized.
EDIT: Just to explain ways in which you could use a reference:
const std::string &text = yourString;
or:
TextManager(const std::string &textRef)
: text(textRef)
{
}
That way, you have a permanent reference to whatever string you have.
Once you have sorted out the initialisation (which other comments can help you with), using a reference will let you do what you want. That is, changes to the referenced std::string will affect your class because they are the same std::string.
You can get similar behaviour using std::string const* instead of std::string const&. As Oli brought out, using a pointer is more flexible. Since a pointer can be null and can be updated using a pointer will allow you to define a default constructor and a (probably compiler generated) assignment operator. Which may not be important in this class but likely will be in some other class you will write (eg if you want to put objects of this class into a std::vector). So you probably are better off using a pointer internally. Though you may wish to still pass a reference to the constructor and take the address of it to initialise the member.
Is there any way to know if an object is a const object or regular object, for instance consider the following class
class String
{
String(const char* str);
};
if user create a const object from String then there is no reason to copy the passed native string and that because he will not make any manipulation on it, the only thing he will do is get string size, string search and other functions that will not change the string.
There is a very good reason for copying - you can't know that the lifetime of the const char * is the same as that of the String object. And no, there is no way of knowing that you are constructing a const object.
Unfortunately, C++ does not provide a way to do what you are attempting. Simply passing a const char * does not guarantee the lifetime of the memory being pointed to. Consider:
char * a = new char[10];
char const *b = a;
String c (b);
delete[] a;
// c is now broken
There is no way for you to know. You could write a class that tightly interacts with String and that creates a constant string pointing to an external buffer (by making the corresponding constructor private and making the interacting class a nested class or a friend of String).
If all you worry about is doing dynamic memory management on a potentially small constant string, you can implement the Small String Optimization (also Small Object/Buffer Optimization). It works by having an embedded buffer in your string class, and copying each string up to some predefined size into that buffer, and each string that's larger to a dynamically allocated storage (the same technique is used by boost::function for storing small sized function objects).
class String {
union {
char *dynamicptr;
char buffer[16];
};
bool isDynamic;
};
There are clever techniques for storing even the length of the embedded string into the buffer itself (storing its length as buffer[15] and similar trickeries).
You could use const_string to do what you're looking for. However, even with const string you have to "tell" it that the string doesn't need to be copied.
const char* foo = "c-string";
boost::const_string bar(foo); // will copy foo
boost::const_string baz(boost::ref(foo)); // assumes foo will always be a valid pointer.
if user create a const object from String then there is no reason to copy the passed native string and that because he will not make any manipulation on it, the only thing he will do is get string size, string search and other functions that will not change the string.
Oh yes there is. Just that it is passes as const doesn't mean that it actually is const outside of the constructor call, and it especially doesn't mean it won't be destroyed while the string object still exists. The keyword const for a function argument only means that the function won't modify or delete it (trying to implement a function that modifies a const argument will result in a compiler error), but there's no way for the function to know what happens outside.
What you're looking for is basically a COW (copy on write) string. Such things are entirely possible, but getting them to work well is somewhat non-trivial. In a multithreaded environment, getting good performance can go beyond non-trivial into the decidedly difficult range.
I'm going to create a class to hold a long list of parameters that will be passed to a function. Let's use this shorter example:
class ParamList{
public:
ParamList(string& a_string);
string& getString(); //returns my_string
private:
string& my_string;
}
My question is this: my_string is private, yet I'm returning the reference to it. Isn't that called something like private pointer leaking in C++? Is this not good programming practice? I want callers of getString to be able to get the reference and also modify it.
Please let me know.
Thanks,
jbu
edit1: callers will use getString() and modify the string that was returned.
Returing a private reference is perfectly okay so long as:
A. That is a const reference, and you have documented when that reference can be invalidated or
B. That reference is intended to be modified (i.e. std::vector<T>::operator[])
While there are useful cases for returning a non-const reference you should usually avoid it. This is covered in Scott Meyers' Effective C++ (3rd Edition, Item 28): Avoid returning "handles" to object internals, if you'd like to take a look.
First off, you need to decide if the ParamList is going to own the string or just "know about it". The way you've written it, with string& my_string, means that it just has a handle onto someone else's string. In that case, it's not (much of) a problem for some to modify the string since ParamList doesn't own it in the first place!
If you want ParamList to have a full master copy of the parameters (depends on the problem you're trying to solve), do something like this:
class ParamList{
public:
ParamList(const string& a_string); // do a strcpy in here.
const string& getString(); //returns my_string
void setString(const string& new_string); //do a strcpy here too.
private:
string my_string;
}
Note that it's probably better to use set and get functions anyway rather than returning a non-const reference, just so ParamList can have a little more control over how its members are modified.