It was careless of me to make such a wrong guess. I did a lot of useless works because I ignored the line where the default constructor is declared on the book. Sorry about that.
=============contents below is the original question=================
I have a question about an example & explanation at C++ Primer 5th, P.292, it is about how to use delegate constructors:
class Sales_data {
public:
//target constructor
Sales_data(std::string s, unsigned cnt, double price) :
bookNo(s), units_sold(cnt), revenue(cnt * price) { }
//delegate constructor that I have question on
Sales_data(std::istream &is): Sales_data() {read(is, *this)}
};
for explaining how this delegate constructor works,the book said:
It delegates to the default constructor , which in turn delegates to the three-argument constructor.
I was confusing about the explanation. I don't get why the delegate constructor delegates a default constructor first , then still need to delegates the target constructor.
For confirming my thought I did some experiments:
First, I have a thought that the target constructor will automatically generate a default constructor, because there is no default constructor declaration in the example code; And I know the default constructor is a must when I have my custom constructor. So I tried to compile the class with some simple test code here:
int main(int argc, char const *argv[]) {
Sale_data item1(std::cin);
print(std::cout, item1);
return 0;
}
and I got a error:
error: no matching function for call to Sale_data::Sale_data()
Then I added the Sales_data() = default, the program printed the correct result.
Next, I deleted my target constructor. However, the program still represents a same result as what I got from the step 2: looks like the default constructor did its job well.
Comparing with what the book explained, my experiment shows that the target constructor has no business with the delegate constructor, in my case. Would you please point out where am I wrong??
Thanks in Advance for your help!
First, I have a thought that the target constructor will automatically
generate a default constructor, because there is no default
constructor declaration in the example code;
There is a default constructor in the book. Just right after the three parameter target consturctor. Did you refer to the wrong code sample?
Sales_data(): Sales_data("", 0, 0) {}
Related
I have seen this question: Attempting to reference a deleted function (VS2013) but it didn't provide me an answer.
I have a member variable in class which its type is ofstream and a constructor which contains string parameter:
class dogs
{
public:
ofstream dogsFile;
dogs(string location)
{
}
};
The following error appears:
Error 2 error C2280: 'std::basic_ofstream>::basic_ofstream(const std::basic_ofstream> &)' : attempting to reference a deleted function c:\users\pc\documents\visual studio 2013\projects\database\database\database.cpp 26 1 Database
I have tried this code again but instead of using string I used char*:
class dogs
{
public:
ofstream dogsFile;
dogs(char* location)
{
}
};
And the error disappeared. Why? why does string makes the error?
Edit:
This is the whole code:
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class dogs
{
ofstream dogsFile;
public:
dogs(string location)
{
}
};
int main(int argc, _TCHAR* argv[])
{
dogs dog = dogs("dog.bin");
return 1;
}
The original answer by Dieter seems to be correct.
I.e. This will compile:
dogs *dog = new dogs("dog.bin");
Your line will not, see his answer about copy constructors.
the dogs("dog.bin") will create an object then "=" will make a copy of it and give it to dog. Can't copy object with ofstream in it.
You can also fix this by using
dogs dog("dog.bin");
instead.
I can't think of this as anything else than a bug in VC++.
The way the dogs class is defined, the compiler should generate an implicit move constructor for it, which will call the move constructor for std::ofstream, which is defined as of C++11.
The rules for when to define an implicit move constructor are specified in the standard in [12.8/9] and [12.8/11]. They're also listed here. I can't see any reason not to declare the implicit move constructor in this case.
Then, the line
dogs dog = dogs("dog.bin");
must invoke a move from the temporary dogs object on the right hand side to the left-hand-side dog (the move may be elided, but the constructor needs to be accessible nonetheless).
In short, everything should work fine.
And it does in Clang 3.5. It doesn't work in GCC, but only because it doesn't have move constructors defined for stream classes (it's not standard-compliant in that respect).
Funnily enough, it works in VC++, as the OP duly mentioned, if the dogs constructor is declared to take anything else but a std::string by value. Change the constructor to any of the following:
dogs(const string& location)
or
dogs(int a) //And change the call accordingly, of course.
or
dogs(A a) //And change the call accordingly (A is a user-defined class).
and everything will work fine in VC++, as it should.
The fact that it doesn't work only for std::string passed by value seems to indicate there's a bug in the compiler. Basically, in that case, and only in that case, the compiler decides not to define the implicit move constructor, which causes the copy initialization to fall back to calling the copy constructor, which causes the error.
If you explicitly define the move constructor, like this:
dogs(dogs&& arg) : dogsFile(std::move(arg.dogsFile)) { }
again, everything works fine, including with the constructor taking a std::string by value.
I can't see any valid reason for VC++ to behave this way.
In class MyClass, I have a member Dialog dialog_.
After MyClass's constructor is called, I want to call a different constructor for dialog_ with parameters that are created in MyClass's constructor (that's why I can't directly call the different constructor for dialog_, but just the default one).
So I tried
dialog_ = Dialog(/* different constr. w/ parameters passed from MyClass */);
But that doesn't work. The error is
Error: no operator "=" matches these operands
operand types are: Dialog = Dialog
So I Googled a bit and found in this SO thread (3rd answer) a code snippet which I tried:
dialog_.~Dialog();
new(&dialog_) Dialog(/* different constr. w/ parameters passed from MyClass */);
And it works. The answer in the thread though states "The value of this does not go beyond purely theoretical though. Don't do it in practice. The whole thing is ugly beyond description."
So what can I do to solve my problem without using that obviously frowned upon piece of code?
I hope you understand what I'm trying to achieve. Thanks!
There are two ways to achieve what you want.
In c++98 you need to defer some of your initialisation to an init() function that you call from the constructor. This is a bit icky because it means a redundant construction and assignment for a number of your member variables.
In c++11 you can call 1 other constructor in the initialiser list, passing computed values (these values can be computed in static functions for cleanliness).
If you provide an example of your constructor code I can show you how to do it.
You can put the Dialog member in a std::unique_ptr and then replace it when you need:
class MyClass {
private:
std::unique_ptr<Dialog> dialog_;
public:
MyClass():
dialog_( /* ... first constructor ... */ ) {}
void setNewDialog(/* parameters */) {
dialog_.reset(new Dialog(/* parameters */) );
}
};
Nothing I've tried is working, so I'll just use
dialog_.~Dialog();
new(&dialog_) Dialog(/* ... */);
even though it's bad
I am working in c++.
my class animation.h is the following:
class Animation
{
public:
Animation(ofVec2f _startLoc, ofVec2f _endLoc, float _speed, float _accel);
virtual ~Animation();
};
then in sceneMusic.h I have another class that calls animation class.
#include "animation.h"
class sceneMusic
{
public:
sceneMusic();
virtual ~sceneMusic();
private:
Animation staveMotion;
};
and sceneMusic.cpp
sceneMusic::sceneMusic()
{
staveImg.loadImage("./sceneMusic/stave_white.png");
staveMotion = Animation(ofVec2f(29, -staveImg.height()), \
ofVec2f(29, 249), 1, 0.1);
}
The above gives the following (expected) error:
src/awards/sceneMusic.cpp|3|error: no matching function for call to ‘Animation::Animation()’|
src/awards/sceneMusic.cpp|5|note: candidates are:|
src/Animation.h|14|note: Animation::Animation(ofVec2f, ofVec2f, float, float)|
src/Animation.h|14|note: candidate expects 4 arguments, 0 provided|
I read alot of threads that suggest I should use initializer lists and do in sceneMusic.cpp
sceneMusic::sceneMusic()
:Animation(ofVec2f(29, -staveImg.height()), \
ofVec2f(29, 249), 1, 0.1)
{
staveImg.loadImage("./sceneMusic/stave_white.png");
}
or something similar.
The problem is that the height of staveImg will only become available once the constructor will be executed.
Also the class sceneMusic does not inherit class animation, therefore I am not sure how the above would work. If I attempt to run the above I get
src/awards/sceneMusic.cpp|4|error: type ‘Animation’ is not a direct base of ‘sceneMusic’|
src/awards/sceneMusic.cpp|4|error: ‘((sceneMusic*)this)->sceneMusic::staveImg.ofImage_<unsigned char>::height’ cannot be used as a function|
src/awards/sceneMusic.cpp|5|error: no matching function for call to ‘Animation::Animation()’|
src/awards/sceneMusic.cpp|5|note: candidates are:|
...
What am I doing wrong ?
thank you for your help
Well, the issue with your second attempt is you'd need to do this:
sceneMusic::sceneMusic()
:staveMotion(ofVec2f(29, -staveImg.height()), \
ofVec2f(29, 249), 1, 0.1)
You specify the member names in the initializer lists. You specify a class name only when you are attempting to call a specific super-class constructor. Animation is not a super-class of sceneMusic.
The following "no matching function for call to Animation::Animation()" occurred for the same reason it would have occurred if you didn't have anything in your initializer list at all: the staveMotion member was still trying to use Animations default constructor (just like the default constructor is used when you declare a variable Animation a;), but Animation does not have a default constructor.
Correcting the error in the initializer list takes care of both errors.
By the way, your second error regarding height(): make sure there's actually a member function named height(). You aren't showing the code but that error seems to indicate that you actually have a member variable named height, not a function.
However, the above still won't fix your issue with having to call loadImage first (thanks chris for reminding me about that in comments).
The easiest solution to that is to revert to your first attempt, and simply provide a default (no parameter) constructor for Animation. As soon as you declare a non-default constructor, the compiler no longer generates a default constructor for you, and you have to explicitly declare/define Animation::Animation() to provide it. That way, staveMotion can be constructed with some default values (and won't have to be constructed in your initializer list) and then assigned to a proper value later.
A second option, by the way, that wouldn't require creation of temporary default Animations first (or perhaps more importantly, wouldn't require you to implement a default constructor that possibly breaks class invariants), would be to have staveImg be a member field of sceneMusic, give it a constructor that takes an image filename and loads the image, and declare it before staveMotion in the member list. You wouldn't need an Animation default constructor for this, and you could initialize everything in the initializer list:
sceneMusic :: sceneMusic () :
staveImg("./sceneMusic/stave_white.png"),
staveMotion(ofVec2f(29, -staveImg.height()), ofVec2f(29, 249), 1, 0.1)
{
}
A variation on that option is to construct the image ahead of time and pass it as a parameter to the sceneMusic constructor. This wouldn't require a new constructor fo staveImg.
A third option, which CantChooseUsernames brought up in the comments, is to make staveMotion a pointer. You can initialize it to NULL and construct a new Animation(...) when necessary without requiring a default constructor. If you do this, don't forget to delete it when you are done. An automatic pointer such as std::unique_ptr<Animation> or one of the other smart pointers (boost has some too) can make that easier on you.
you need a default constructor class Animation since you provide parameter constructor ,the compiler would not generate one for you
Animation() {}
Is it possible to have 1 constructor have the option of being a default constructor if a parameter is not passed in.
Example, instead of having 2 constructors, where 1 is the default constructor and another is a constructor that initializes numbers passed in, is it possible to only have 1 constructor that if a value is passed in, set that value to a member function, and if no value is passed in, set the member function to a number.
example:
WEIGHT.H file:
class Weight
{
public:
Weight() { size = 0; }
Weight(int a) : size(a) {}
int size;
};
MAIN.CPP file:
int main(void)
{
Weight w1;
Weight w2(100);
}
I've been working on different school projects and they all require to have different types of constructors, and i'm wondering if there is a way to only have it once so it saves time.
Thanks for the help.
Yes, a constructor parameter may have a default argument, just like other functions can. If all of the parameters of a constructor have default arguments, the constructor is also a default constructor. So, for example,
class Weight
{
public:
explicit Weight(int a = 0) : size(a) { }
int size;
};
This constructor may be called with a single argument or with no arguments; if it is called with no arguments, 0 is used as the argument for the a parameter.
Note that I've also declared this constructor explicit. If you have a constructor that may be called with a single argument, you should always declare it explicit to prevent unwanted implicit conversions from occurring unless you really want the constructor to be a converting constructor.
(If you aren't familiar yet with converting constructors or implicit conversions, that's okay; just following this rule is sufficient for most of the code you'll ever write.)
Yes its possible as suggested by James but as you know if you are not defining the Default constructor the compiler would take over the definition part if you have not provided any constructor definition.
Its not an issue as such but its a better practice to define the Default constructor for proper initialization of values.
Google C++ Style guide also recommends it.
Please help me with the following problem:
I have the following classes:
class ChemicalElement
{
private:
std::string _name;
void Init(const std::string& name);
public:
ChemicalElement(const std::string& name);
ChemicalElement(const ChemicalElement& ce);
};
class CombinationRule
{
private:
ChemicalElement _ce1;
ChemicalElement _ce2;
void Init(const ChemicalElement& ce1, const ChemicalElement& ce2);
public:
CombinationRule(const ChemicalElement& ce1, const ChemicalElement& ce2);
CombinationRule(const CombinationRule& rule);
};
The implementation is obvious. I intended to initialize the CombinationRule using the Init method to minimize code duplication. Alas, if I do not use "member initialization list" in each constructor the compiler complains with "error C2512: 'ChemicalElement' : no appropriate default constructor available". Is there an elegant way to solve this error instead of using a default constructor or member initialization list?
BTW: if there are any other problems in the classes definition please add it too. Since I'm revisiting C++ I want to be aware of them.
You should implement constructors of CombinationRule as follows so they will use appropriate constructors of ChemicalElement:
CombinationRule::CombinationRule(const ChemicalElement& ce1,
const ChemicalElement& ce2) : _ce1(ce1), _ce2(ce2)
{
...
}
CombinationRule::CombinationRule(const CombinationRule& rule) :
_ce1( rule._ce1 ), _ce2( rule._ce2 )
{
...
}
I think you are required to put a default constructor in any class where you define any other constructors, if you want to use objects of that class in any kind of array or container. The default constructor's implementation can just be an empty/no-op method though.
You shouldn't need to put in a member initialization list (although using a member initialization list can be more efficient in some cases, since that way your member variables are only initialized once, instead of being initialized once via their default constructor, and then written to a second time by your Init() method)
I think you want this
ChemicalElement * ce1;
I say this because I think its trying to run the default constructor on your CombinationRule and in turn needs to get a ChemicalElement for ce1 and ce2 ... but I could be wrong.
Pretty sure Krill's way is the way to specify the constructor of a variable for a specific constructor BUT i said f that and just made it so ce1 doesn't need to be constructed by the compiler :)
In this particular example I would go on with duplication (it's just writing two initializers, nothing to get obsessive about).
But assuming the real story is more complex: use OO facilities to avoid code duplication.
class CombinationRule : public ElementPair ...
or
class Combination { ElementPair twoElements; ...}
Where ElementPair contains two ChemicalElements and a single constructor (with common code), and Combination rule constructors initialize using constructor of ElementPair.
There are other approaches: initializing members with some InvalidChemicalElement instance or using pointers (auto_ptr) with NULL for InvalidChemicalElement.