Is there any difference (no matter how tiny is) between those three methods of defaulting the constructor of a class:
Directly in the header using {}:
//foo.h
class foo{
public:
foo(){}
}
Directly in the header using default keyword:
//foo.h
class foo{
public:
foo()=default;
}
In the cpp using {}
//foo.h
class foo{
public:
foo();
}
//foo.cpp
#include "foo.h"
foo::foo(){}
Yes, there is a difference.
Option 1 and 3 are user-provided. A user-provided constructor is non-trivial, making the class itself non-trivial. This has a few effects on how the class can be handled. It is no longer trivially copyable, so cannot be copied using memcpy and the like. It is also not an aggregate, so cannot be initialized using aggregate-initialization
A fourth option is the following:
//foo.h
class foo{
public:
foo();
}
//foo.cpp
#include "foo.h"
foo::foo()=default;
Although this may seem analogous to your second example, this is actually user-provided as well.
Functionally, the defaulted constructor does the same thing as your foo(){}, as specified in [class.ctor]/6.
Related
I'd like to do declare a member object within the class declaration within my header file. I want to defer the calling of the member's constructor until the corresponding source file.
This is ideally what I'd like, just for illustration:
// foo.h
class Bar(string First, string Second);
class Foo : public Base {
public:
Foo(int a);
Bar b; // I don't want to construct here!
...
// foo.cc
Foo::Foo(int a)
: base(a)
, b("first", "second") // <-- construct here
{}
edit: The code above is calling the "default constructor" for Bar. I get:
error: could not convert ‘{arg}’ from ‘<brace-enclosed initializer list>’ to ‘Bar’
Bar bar;
Changing the type of b to a pointer will ripple through too many things.
Changing it to a REFERENCE is probably tenable. In the code below, since no constructor is called in the header file, that's okay for my needs!
// foo.h
class Bar;
class Foo : public Base {
public:
Foo(int a);
Bar& b; // now it's a non-constant reference, but unassigned
...
// foo.cc
Foo::Foo(int a)
: base(a)
, b{"first", "second"} // <-- construct here
{}
However, this results in the error: non-const lvalue reference to type 'Bar' cannot bind to an initializer list temporary. That makes sense too.
I guess I'm asking how would you do this? Is something like std::reference_wrapper going to be useful?
C++11 is a restriction.
The constructor of a member object is called from all constructors of the containing class. That includes compiler-generated constructors.
Hence, you need to make sure that the definitions of all these constructors are in foo.cc. Now you only show Foo::Foo(int), but that's not the constructor which is causing the problem.
I can and do include the full definition
It's exceedingly difficult to get a straight response to you so I'll go with that quote specifically and assume you meant you have a fully defined Bar type before your Foo definition.
If that's the case, your first part of the code does work as intended (once you fix the weird syntax and semantic and every other kind of errors, of course). Specifically, this works as expected:
#include <string>
using namespace std;
struct X {
X(string a, string b) {}
};
struct Y {
X x;
Y() : x("a", "b") {}
};
This does not work
When I don't have a blank constructor in my class the code will not run causing an error saying no default constructor exists for class.
#include <iostream>
class myClass
{
public:
myClass(int val)
:x(val)
{}
private:
int x;
};
int main()
{
myClass random;
return 0;
}
This works
#include <iostream>
class myClass
{
public:
myClass(int val)
:x(val)
{}
myClass()
{}
private:
int x;
};
int main()
{
myClass random;
return 0;
}
This is because when you try to instantiate the object myClass random, you are trying to invoke the default constructor which you do not have.
If you changed it to myClass random(3)( basically trying to invoke the constructor that you have), you would see that the compiler would have no problems.
If you want myClass random to compile fine, then you must have a default constructor in your class.
Once you declare a constructor in a class (any constructor), the compiler won't automatically generate a default constructor for you (this is what you're calling the blank constructor).
If you don't want to implement the default constructor (generally a good idea if you just want the default behavior), you can tell the compiler to generate it for you as of C++11.
class myClass {
public:
myClass(int val)
:x(val)
{}
myClass() = default; // the compiler handles the implementation
private:
int x;
};
In the first case you have defined a parameterized constructor. When a constructor is defined the compiler now does not automatically define a default constructor like before.
If no constructor is defined the compiler automatically defines a default constructor but if another constructor is defined the compiler will not do so.
i.e. in first case a default constructor does not exist. In the second case you have defined one and hence has no errors.
See default constructor.
If no user-declared constructors of any kind are provided for a class type, the compiler will always declare a default constructor as an inline public member of its class.
However, there's a constuctor declared in your class, thus the compiler won't declare a default constructor. You have to explicitly declare one yourself.
#include <iostream>
#include <conio.h>
using namespace std;
class Base
{
int a;
public:
Base(const Base & b)
{
cout<<"inside constructor"<<endl;
}
};
int main()
{
Base b1;
getch();
return 0;
}
This gives an error. no matching function for call to `Base::Base()'
Why?
The default constructor is only generated if you don't declare any constructors. It's assumed that if you're defining a constructor of your own, then you can also decide whether you want a no-args constructor, and if so define that too.
In C++0x, there will be an explicit syntax for saying you want the default constructor:
struct Foo {
Foo() = default;
... other constructors ...
};
It does not hide the default constructor, but declaring any constructor in your class inhibits the compiler from generating a default constructor, where any includes the copy constructor.
The rationale for inhibiting the generation of the default constructor if any other constructor is present is based on the assumption that if you need special initialization in one case, the implicitly generated default constructor is most probably inappropriate.
This is a very noobish mistake, but I dont know whats happening here.
There are loads of pimpl examples but I dont understand why this isn't working (this was one of the examples more or less but I dont see the difference).
I have a very simple Pimpl example, but it wont work.
// Foo.hpp
#include <boost/scoped_ptr.hpp>
class Foo
{
struct Bar;
//boost::scoped_ptr<Bar> pImpl;
Bar* pImpl;
public:
Foo();
~Foo() {}
int returnValue();
private:
};
and
// Foo.cpp
#include "foo.hpp"
struct Foo::Bar
{
Bar() {}
~Bar() {}
int value;
};
Foo::Foo() : pImpl(new Bar())
{
pImpl->value = 7;
}
int Foo::returnValue() {
return *pImpl->value;
}
Compiling this gives me the error.
C2100: illegal indirection.
Thanks.
int returnValue() should be a member function:
// vvvvv
int Foo::returnValue() {
return pImpl->value; // no need to dereference, value isn't a pointer
}
You need to define your constructor, copy-constructor, copy assignment operator, and destructor after the implementation class has been defined. (Otherwise the implicit destructor is dangerous, and scoped_ptr won't let you do that):
// Foo.hpp
#include <boost/scoped_ptr.hpp>
class Foo
{
struct Bar;
boost::scoped_ptr<Bar> pImpl;
public:
Foo();
~Foo();
int returnValue(); // could be const (so should be)
private:
// just disable copying, like scoped_ptr
Foo(const Foo&); // not defined
Foo& operator=(const Foo&); // not defined
};
And:
// Foo.cpp
#include "foo.hpp"
struct Foo::Bar
{
int value;
};
Foo::Foo() :
pImpl(new Bar())
{
pImpl->value = 7;
}
Foo::~Foo()
{
// okay, Bar defined at this point; scoped_ptr can work
}
int Foo::returnValue()
{
return pImpl->value;
}
As an aside, you may have a problem using boost::scoped_ptr for a pImpl because your pImpl is forwardly declared and you may find that the class needs to be fully visible in order to call scoped_ptr's destructor (which deletes the underlying).
Some compilers will allow you to work around this by putting the body of your destructor in the compilation unit (the .cpp file) where the class is visible.
The simplest solution is that if your destructor has to be implemented anyway you may as well just use a raw pointer and have your destructor delete it. And if you want to use something from boost to help you, derive your outer class from boost::noncopyable. Otherwise ensure you handle copy-construction and assignment properly.
You can use shared_ptr to your pImpl. You can then copy your outer class around happily although they share the same underlying unless you overload the copy-constructor and assignment operator to do otherwise.
Should SomeClass* initialEl = new SomeClass[5]; necessarily compile, assuming SomeClass does not have a non-publicly declared default constructor? Consider:
/*
* SomeClass.h
*
*/
#ifndef SOMECLASS_H_
#define SOMECLASS_H_
class SomeClass
{
public:
SomeClass(int){}
~SomeClass(){}
};
#endif /* SOMECLASS_H_ */
/*
* main.cpp
*
*/
#include "SomeClass.h"
int main()
{
SomeClass* initialEl = new SomeClass[5];
delete[] initialEl;
return 0;
}
Assuming SomeClass has a publicly accessible default constructor, yes.
Note that there is a difference between
having a publicly accessible default constructor (what i said) and
not having a non-publicly declared default constructor (what you said)
For the following class 2. is true but 1. is not:
class A {
SomeClass(const SomeClass&) {}
};
This is due to §12.1/5 (C++03):
If there is no user-declared constructor for class X, a default constructor is implicitly declared.
An implicitly-declared default constructor is an inline public member of its class.
With your update, SomeClass doesn't have a default constructor. You didn't declare one and because you have declared another constructor the compiler won't declare it implicitly either.
If you need one you have to implement it yourself:
class A {
public:
SomeClass(int) {}
SomeClass() {}
};
Or let another constructor qualify as a default constructor:
class A {
public:
SomeClass(int=0) {}
};
No, it won't compile without a default constructor. There is no compiler-generated default constructor in this case, because you have defined another constructor. "The compiler will try to generate one if needed and if the user hasn't declared other constructors." -- The C++ Programming Language, Stroustrup
If you really want to use new SomeClass[5], you'll have to provide a default constructor as well.