I have created a simple class that takes an argument to the constructor as shown below.
class Jam
{
int age;
std::string name;
Jam *jam;
Jam(std::string argName) {
name = argName;
}
};
It takes the argument and initializes the Jam's name to the parameter passed. The only problem is that I'd like to be able to pass another copy of Jam to the constructor so I can initialize its pointer to an existing class by copying the values. Normally in C++ you could specify Jam *jam = new Jam(existingJam); and it would be copied by default, but since I already have std::string argName as a parameter, it refuses to let me do this.
I read an article here that explains how to create your own copy constructor, but it is rather tedious and involves copying each class member individually which seems like it would not make much sense for a class with 10+ data members. Is there a better way to do this than initializing each member individually?
Jam::Jam(std::string argName, Jam *argJam)
{
age = argJam->age;
//etc...
}
[It's quite possible I don't understand what you're asking, but here goes...]
The compiler provides a copy constructor if you don't write one yourself. Its behaviour is to copy each member variable in turn.
Related
I'm currently learning C++ and reading through "C++ Primer 5th Edition". I just started learning about constructors and I'm having a bit of a problem that I can't figure out.
#ifndef SALES_DATA_H
#define SALES_DATA_H
#include <string>
struct Sales_data
{
//default constructor
Sales_data(const std::string &s, unsigned n, double p):
bookNo(s), units_sold(n), revenue(p*n) { }
//new members: operations on Sales_data objects
std::string isbn() const { return bookNo; }
Sales_data& combine(const Sales_data&);
double avg_price() const;
//data members
std::string bookNo;
unsigned units_sold;
double revenue;
};
I'm pretty sure that the default constructor I wrote is correct (considering it's the one written in the book), but obviously I'm missing something here. I don't see any syntax errors or anything and all of the built-in members are being initialized so I have no idea what's wrong.
EDIT :
I just found out that it's not my header file giving the error, it's actually my source file. When I create a Sales_data object like:
Sales_data total;
it gives me the "No appropriate default constructor available" error. I'm still unsure as to what's wrong considering the author gave three ways to write a default constructor, these are them:
struct Sales_data {
// constructors added
Sales_data() = default; //Number 1
Sales_data(const std::string &s): bookNo(s) { } //Number 2
Sales_data(const std::string &s, unsigned n, double p): //Number 3
bookNo(s), units_sold(n), revenue(p*n) { }
If those aren't default constructors, then what exactly are they/is their purpose?
A default constructor is a constructor that can be called without passing any argument.
This means that it must take no parameters or that all of them must have a default value.
The default constructor is needed for example when you write
MyClass x;
because the compiler must be able to generate code to build such an object without any arguments.
Also standard containers may require a default constructor depending on how you use them: for example if you use std::vector::resize the library can be asked to increase the size of a vector containing your class instances, thus it must be able to create elements without providing any argument.
The problem isn't related to default constructors. The problem indeed is in Sales_data total;. What's the book number, sales price and number sold for total? You must provide them when constructing total.
The constructor of your class takes three parameters, those must be provided when you try to construct an object. Your current variable declaration doesn't provide any parameters:
Sales_data total;
Because there are no parameters provided, the compiler tries to use a constructor that doesn't take any parameters. Such a constructor is also called "default constructor". Your class doesn't have a constructor without parameters, so this doesn't work.
To use the existing constructor, you have to provide the parameters when you create the object:
Sales_data total("books", 28, 15.99);
Alternatively you could add a constructor to Sales_data that doesn't take any parameters (a default constructor), and initializes the class with some default values.
Another question from reading "Accelerated C++" by Andrew Koenig and Barbara E. Moo, and I'm at the chapter about constructors (5.1), using the example as before.
They write
we'll want to define two constructors: the first constructor takes no arguments and creates an empty Student_info object; the second takes a reference to an input stream and initializes the object by reading a student record from that stream.
leading to the example of using Student_info::Student_info(istream& is) {read(is);} as the second constructor which
delegates the real work to the read function. [...] read immediately gives these variables new values.
The Student_info class is
class Student_info {
public:
std::string name() const (return n;}
bool valid() const {return !homework.empty();}
std::istream& read(std::istream&);
double grade() const;
private:
std::string n;
double midterm, final;
std::vector<double> homework;
};
Since read is already defined as a function under the Student_info class, why is there a need to use a second constructor - isn't this double work? Why not just use the default constructor, and then the function since both are already defined?
It isn't double work on the contrary it simplifies the object initialization for the caller who instantiates the class
If you create the class with a single constructor every time you have to do
std::istream is = std::cin;
Student_info si();
si.read(is);
// si.foo();
// si.bar();
// si.baz();
Maybe some other operations can be added that can be done in constructor. So you don't have to write them again when you need to instantiate the class. If you create 10 instances you will have to write
( 10 -1 = ) 9 more lines and this isn't a good approach for OOP
Student_info::Student_info(istream& is)
{
read(is);
//foo();
//bar();
//baz();
}
But when you define two constructors like above, you can use the class like
std::istream is = std::cin;
Student_info si(is);
One of the main goals of OOP is writing reusable and not self repeating code and another goal is seperation of concerns. In many cases person who instantiates the object doesn't need to know implementation details of the class.
On your example read function can be private when its called inside constructor. This reaches us another concept of OOP Encapsulation
Finally this isn't double work and its a good approach for software design
My question is since read is already defined as a function under the Student_info class, why is there a need to use a second constructor - isn't this double work?
The second constructor takes an argument from the caller and passes it on to the read function. This allows you to directly instantiate a Student_info with an std::istream.
std::istream is = ....;
Student_info si(is); // internally calls read(is)
as opposed to
std::istream is = ....;
Student_info si;
si.read(is); // how could we use is if this call isn't made? Now we have to read some docs...
Why not just use the default constructor, and then the function since both are already defined?
Because it is better to construct objects such that they are in a coherent, useful state, rather than construct them first and then initialize them. This means users of the objects do not have to worry about whether the thing can be used or must first be initialized. For example, this function takes a reference to a Student_info:
void foo(const Student_into& si)
{
// we want to use si in a way that might require that it has been
// initialized with an istream
si.doSomethingInvolvingInputStream(); // Wait, what if the stream hasn't been read in?
// Now we need a means to check that!
}
Ideally, foo should not have to worry about the object has been "initialized" or made valid.
I am working on a project which handles the Data of a Library Section having multiple classes. Interface of interest of a class here is this.
class Author
{
private:
//data members
public:
Author (string _name) ;
Author (string _name, int _books) ;
} ;
Data is present with at least the name of the author, and no. of books may come along. I cannot have a default constructor here naturally. But if create a static array like this.
Author auth_arr[100] ;
Compiler gives me error due to absence of default constructor. But this statement is invalid as well.
Author auth_arr[100] ("Jacob") ;
Is there any method by which i can create this array and call the constructor of my choice, instead of making another method?
You can do this to a very limited extent. The trick is to call those constructors explicitly inside curly braces inside separated by commas, and instantiate the static array this way.
Author auth_arr [3] = {Author(“Kevin”, 7) ,Author(“Martha”) ,Author(“Shuan”, 15) } ;
But this method is literally a nightmare. You can do this for a size 5 or 10 array but not for a 50 size array or any more than that. So the better option is to make another method and call it passing the details as its arguments. Remember this is only for static arrays as you asked. For dynamic arrays, which are more frequently used than static, even this method is not applicable.
C++ does not allow you another method to call constructors of your choice. So default constructor should be defined in the class to get called at instantiation. Then, an appropriate method could be called afterwards with the data.
Another better thing would be to use std :: vector. Its detail you can find in another similar question here.
Constructors and array of object in C++
Are you really sure default c-tor has no sense here?
I would suggest this solution:
class Author
{
private:
//data members
public:
static string default_name;
Author (string _name = default_name);
Author (string _name, int _books);
} ;
string Autor::default_name = "NOBODY";
If you really insist to have 100 Jacobs, then do it in this way:
Author::default_name = "Jacob";
Author auth_arr[100];
Author::default_name = "NONE";
[UPDATE1]
However this works for local arrays only.
With a little trick you can use it for static/global arrays. I am not going to present it - because there is another solution to make static array of class without default constructor which I understand from your comment is your goal ;) With little help of macros you can even generate thousands of objects:
#define MAKE_10(X) X,X,X,X,X,X,X,X,X,X
Author auth_arr[101] = {
MAKE_10(MAKE_10(Author("Jacob", 0))),
Author("Jacob", 0)
};
I am a beginner in C++ and am trying to learn it by looking at examples.
Here is an example definition for a class that I don't understand the meaning completely:
class MyClass{
public:
std::string name;
void *data;
MyClass(const std::string& t_name, void *t_data) : name(t_name), data(t_data) {}
};
Here is what I understand:
name and *data are variables of the class and, MyClass(...) is the constructor. The meaning of : is the left side class is derived from the right hand side class. However, what is the meaning of this part of the code:
MyClass(const std::string& t_name, void *t_data) : name(t_name), data(t_data) {}
Here are the questions:
what are "t_data" and "t_name"? Are they initial values for "data" and "name"? what is the reason t_ is used here?
what is the meaning of : in the above line?
what is {} at the end of that line?
Thanks for the help.
TJ
what are "t_data" and "t_name"? Are they initial values for "data" and "name"?
They are the arguments passed to the constructor. If an object were created as
MyClass thing("Fred", some_pointer);
then, in the constructor, t_name has the value "Fred" and t_data has the value of some_pointer.
what is the reason t_ is used here?
Some people like to tag the arguments to give them different names to the class members, but there's no need to do that unless you want to.
what is the meaning of : in the above line?
That marks the start of the initialiser list, which initialises the class member variables. The following initialisers, name(t_name), data(t_data) initialise those members with the constructor's arguments.
what is {} at the end of that line?
That's the constructor's body, like a function body. Any code in their will be run after the members have been initialised. In this case, there's nothing else to do, so the body is empty.
It is good C++ practice to use initializer lists to initialize members.
t_name, t_data are the parameter names.
The "t_" prefix is merely used to distinguish it from the similarly named member fields.
The members are being initialized using syntax that resembles a function call, but it is a proper initialization/construction, so you should think of it that way.
The colon signals the beginning of an initializer list
The empty braces {} designate that the body of the constructor (which happens after the members are initialized) is empty.
MyClass(const std::string& t_name, void *t_data) : name(t_name), data(t_data) {}
is constructor of your class, and you should initialize your class with a string and void* parameter, then you initialize your class fields (name and data) with your passed parameters
This is a somewhat compressed example for a beginner, but you're asking good questions.
1) t_data and t_name are the parameters going into the constructor. When you create an instance of this class, you'll do something like:
MyClass * myNewClassInstance = new MyClass("My name", &myData);
Now the constructor has "My name" (in std::string form) as t_name and a pointer to myData as t_data.
2) The colon here does not refer to a derived class. Here it says that an "initializer list" is to follow. Check out Prashant's answer's link, or do a little digging about this. Basically, this is setting the member variable name to t_name (which is the std::string that we passed into the constructor in the above example), and data to t_data (the void pointer). (see additional notes below)
3) The {} is the actual definition of the constructor. It's empty -- there's no code here. So all the constructor will do is initialize the member variables (as defined by the initializer list), and nothing more.
Now let's look at the exact same class in a more beginner-friendly format:
// The declaration of MyClass. This would often show up in a header (.h) file
class MyClass {
public:
// Member variables
std::string name;
void * data;
// Declaration of constructor -- we haven't defined what actually does here, just
// what parameters it takes in.
MyClass(const std::string& t_name, void * t_data);
}
// We declared what the class "looks like" above, but we still have to define what
// the constructor does. This would usually show up in a .cpp file
// This is the constructor definition. We have to specify that it's part of the
// The extra "MyClass::" specifies that it's part of the MyClass namespace that we
// declared above.
MyClass::MyClass(const std::string& t_name, void * t_data)
{
// Set our member variables to what was passed in.
this.name = t_name;
this.data = t_data;
}
The above version does exactly the same thing (with some subtle differences between initializer lists and traditional initialization in the constructor that you probably don't care about yet -- again, see other references regarding this if you're curious).
It's pretty obvious that this takes up a lot more space, and that's exactly why the more compressed format is often used. But when you're just starting out, it makes things a lot more clear doing it this way. It's important to understand the difference between a declaration and a definition when it comes to functions (i.e. the constructor), because the example you posted does both at the same time when often they are separated.
I am a beginner in C++ and am trying to learn it by looking at examples.
For whatever reason, this is harder to do in C++ than it is in Perl, Python, Java, or even C. I don't recommend this course; instead, you might invest in a good book.
Here is what I understand:
Let's start with that. I don't think you understand as much as you claim to.
name and *data are variables of the class
No. name and data are variables of the class. Their types are std::string and void*, respectively.
MyClass(...) is the constructor.
Yes.
The meaning of : is the left side class is derived from the right hand side class.
No, : means different things in different contexts. In the context in which it is used in your sample, it indicates that an initializer list follows.
However, what is the meaning of this part of the code:
what are "t_data" and "t_name"?
They are local variables in the constructor function. Specifically, they are the passed-in parameters to the function.
Are they initial values for "data" and "name"?
That is how they are being used in this sample. Specifically, they are being passed to the data and name initializers in the initializer list.
what is the reason t_ is used here?
This is purely the convention of this particular author. I've never seen that convention before.
what is the meaning of : in the above line?
It introduces an initializer list. This construct is only used in constructor member functions. Each named member is initialized by the values listed. (Note: the values do not need to come from parameters -- they can be any legal expression, so: MyClass(int ii) : i(ii), j(cos(0) / 2), k(&global_variable) {} might be a legitmate constructor. )
what is {} at the end of that line?
The body of the constructor member function. Since all of the work of the constructor is being done in the initializer list, the body of the function is empty.
This question already has an answer here:
Closed 11 years ago.
Possible Duplicate:
The Definitive C++ Book Guide and List
i have a lot of questions about declaration and implementation, according to most (books, tutorials, blog entries) a class declaration with constructor, methods and member functions:
class Book
{
public:
Book(const string & author_,
const string & title_,
const string & publisher_,
double price_,
double weight_);
string getName()
{
string name;
name = author + ": " + title;
return name.substr(0, 40);
}
double getPrice();
double getWeight();
private:
string author, title, publisher;
double price, weight;
};
i understand all the the access level, the Constructor, reference operator (pointer too!), the pointer operator, but when I read things less trivial like:
class Type
{
public:
enum TypeT {stringT, intT, doubleT, unknownT};
// 1. which means "explicit"?
// 2. what's ": typeId(typeId_)"? after the Ctor declaration
explicit Type(TypeT typeId_) : typeId(typeId_) {}
// 3. "const" after the declaration which means?
BaseValue * newValue() const
{
return prototypes[typeId]->clone();
}
TypeT getType() const
{
return typeId;
}
static void init();
{
prototypes[stringT] = new Value<string>("");
prototypes[intT] = new Value<int>(0);
prototypes[doubleT] = new Value<double>(0);
}
private:
TypeT typeId;
static vector<BaseValue *> prototypes;
};
I feel lost and really have not found clear information about the above points.
Addition to answering my question, if you know somewhere where they have these "tricks" of language
A good introductory book to C++ should answer your questions.
explicit means the constructor must be mentioned explicitely in the code, the type cannot be constructed automatically from another type when required.
Member initialization. The class member is not constructed with its default constructor, but rather the arguments given here.
The method can be called on a const object.
1) By default, c++ will assume that any constructor taking one argument of another type can be used as an "implicit conversion" from the arg's type to the constructor's type; in your example, this would allow you to pass a TypeT into any function expecting a Type, and the constructor would assume you want it to run the Type(TypeT) constructor before actually calling the function.
the explicit keyword prevents that from happening; it tells the compiler that you only want that constructor run when you specifically call it.
2) in between the prototype of the constructor and its body, you can (and, for the most part, should) provide an initializer list; When a constructor is run, the system initializes every parent, then every contained member before running the body of the constructor. The initializer list tells the compiler which constructor you want to be run on a given member variable; in the case of your example, you're running the copy constructor on typeId.
If you don't provide an entry in the initializer list for a given member, the system will simply run the default constructor on that member before entering the body of the original class. This means that, should you assign to the member within the body of your class constructor, you'll be writing to that member's memory twice. This is necessary sometimes, but for many cases is simply wasteful.
3) const at the end of a method prototype makes a guarantee to the compiler that that method will not modify any of the member variables within the class instance when it is called. This allows the method to be called on const instances of your class, and, just like placing const on any variables that will remain unchanged, should be done whenever possible to guarrantee correctness and type safety.
As for which books to read, the link in your question's comments would be a good place to start. Since you seem to understand the barebones basics of the language, I would recommend starting with "Effective C++". It presents a list of best practices for C++, and is aimed at someone who understands the C aspects of the language.