Sometimes I don't want to provide a default constructor, nor do I want the compiler to provide a system default constructor for my class. In C++ 11 I can do thing like:
class MyClass
{
public:
MyClass() = delete;
};
But currently my lecturer doesn't allow me to do that in my assignment. The question is: prior to C++ 11, is there any way to tell the compiler to stop implicitly provide a default constructor?
I would say make it private.. something like
class MyClass
{
private:
MyClass();
}
and no one(from outside the class itself or friend classes) will be able to call the default constructor. Also, then you'll have three options for using the class: either to provide a parameterized constructor or use it as a utility class (one with static functions only) or to create a factory for this type in a friend class.
Sure. Define your own constructor, default or otherwise.
You can also declare it as private so that it's impossible to call. This would, unfortunately, render your class completely unusable unless you provide a static function to call it.
Since c++11, you can set constructor = delete. This is useful in conjunction with c++11's brace initialization syntax {}.
For example:
struct foo {
int a;
foo() = delete;
foo(int _a) {
// working constructor w/ argument
}
};
foo f{}; // error use of deleted function foo::foo()
foo f{3}; // OK
see https://en.cppreference.com/w/cpp/language/default_constructor#Deleted_implicitly-declared_default_constructor
Additionally to declaring the default constructor private, you could also throw an exception when somebody tries to call it.
class MyClass
{
private:
MyClass()
{
throw [some exception];
};
}
Related
I'm trying to initialize a class member, where in which the member is an instance of another class. Visual studio seems to think I'm declaring a function member:
class OtherClass {
OtherClass();
OtherClass(string Foo);
}
class MainClass {
// This Compiles. Default constructor used
OtherClass Instance1;
// Does not compile. Visual studio thinks I'm declaring a function member that returns an OtherClass.
OtherClass Instance2("Foobar");
}
I realize that I can accomplish what I want with a member initialization list like so:
class MainClass {
OtherClass Instance2;
MainClass() : Instance2("Foobar") {}
}
I'm just confused by the fact that, in the first example, the compiler understands that I'm initializing an OtherClass member when I use the default constructor, but it thinks I'm declaring a function if I try to use the constructor that expects a string. Could someone please explain the reasoning behind this and if there is another work-around I'm unaware of?
Update: This declaration ambiguity has a name: Most Vexing Parse
An in-class member initializer must either use an equal sign or {curly braces}.
So:
OtherClass Instance2 = "Foobar";
or:
OtherClass Instance2{ "Foobar" };
My C++ compiler give me an error "no default constructor exists for class Foo" when I try the following.
MyClass::MyClass(const Foo& foo)
{
...
}
If I'm passing a reference, the object should already be initialized, correct? And it's not a problem with copy constructors, because I defined one explicitly. So why would one need a default constructor to pass a reference?
The only thing I've been able to think of is that it might not know how much memory to allocate for it. If that's the problem, is there a way to tell the compiler that I only ever intend to allocate this object dynamically? I haven't been able to find any answers online for this, and I would really appreciate some help.
EDIT: I'm just going to edit in my actual code.
MemberManager.cpp:
#include "MemberManager.h"
MemberManager::MemberManager(const NodeManager& nodeSet, std::vector<int> cctMat, int n)
{
for(int i = 0; i < n; i++)
{
memSet[i] = Member();
}
}
NodeManager.h
#include "Node.h"
class NodeManager
{
public:
//constructors
NodeManager(std::vector<double> crdMat, std::vector<Constraint> cstMat, int n):
nodeSet(n) {};
//copy
NodeManager(const NodeManager& src):
nodeSet(src.nodeSet) {};
}
My precise error message is a red underline under the first body bracket of MemberManager::MemberManager(...) and it says no default constructor exists for NodeManager. This is my intent, but I don't understand WHY it would need a default constructor.
You don't need a default constructor to pass an object by reference. Your code must be doing something else that requires such a thing.
My guess is that MyClass has a member of type Foo. If it isn't default-constructible, then it needs to be initialised in its declaration, or in the constructor's initialiser list:
MyClass::MyClass(const Foo& foo) : foo(foo) { ... }
^^^^^^^^
initialiser list
This assumes that the member is called foo, and that it's supposed to be initalised by copying the function parameter.
It would be helpful to know what compiler you are using, which standard of c++ it complies to and if you have other constructors for MyClass.
What I can imagine is that the compiler does not generate a default constructor MyClass() because you have defined another constructor. Should the compiler ever want to generate a default object of class MyClass like in
class MyClass mc;
The only way to accomplish this in the absence of MyClass::MyClass() is to think the code line above as
class MyClass mc( Foo() );
This requires class Foo to have a default constructor.
I would have made this a comment, but I'm not yet allowed to.
Is there a way to achive that behaviour on compilers that don't support C++11 ?
class Meow
{
public:
Meow(const Meow&) = delete;
};
Making the constructor private is not a solution, because then you can do something like that:
class Meow
{
private:
Meow(const Meow&);
public:
Meow();
void doSomething()
{
Meow kitty;
Meow secondKity(kitty); // allowed
}
};
If the constructor is marked as deleted the above is not possible.
Making the constructor private is the pre-C++11 solution. Your second code is not valid because the copy constructor doesn't have a definition (presuming you don't give it a definition elsewhere). Yeah, it's not the best solution, but that's why = delete was introduced.
You may want to use boost::noncopyable to be more explicit about it, but it only does the same thing.
You can easily emulate that with a private, not defined copy constructor.
Instead of a nice error message you'll get a linker error as the copy constructor won't be found.
Another alternative is boost::noncopyable (http://www.boost.org/doc/libs/1_55_0/libs/utility/utility.htm#Class_noncopyable), which wraps this technique in a nice little helper class.
Observation: The constructor of ClassMain needs to call Init before it can constructor a member variable a. Since the ClassA has no default constructor, the code doesn't compile.
ClassA
{
public:
// This class has no default constructor
ClassA(...){}
};
class ClassMain
{
public:
ClassMain(...) {
Init(...);
a = ClassA(...); // error: ClassA has no default constructor
// a has to been constructed after the Init is called!
}
ClassMain(...) {
Init(...);
call other functions
a = ClassA(...);
}
private:
// initialize environment
void Init(...) {}
private:
ClassA a;
};
Question> The simple solution is to provide a default constructor for ClassA. However, I would like to know whether there is a better solution to address the issue above?
The better solution is not to require an Init function at all. You're trying to reinvent constructors, and breaking their design in the process.
If Init does too much work for a constructor, then do it outside and pass the resulting resources into ClassMain as a constructor argument; notice how you're already doing all the work in the constructor's scope anyway, thereby not gaining anything appreciable over proper initialisation.
Of course, if you must perform a ton of work before initialising a, and you cannot pass in a ClassA& from the outside and initialise from that, then you're simply going to have to have a be an indirect member.
There is one nasty workaround you could use: have Init actually be a base constructor...
The obvious solution is to call Init() from the initializer list of an early member or a base class. Once this subobject is constructed its results can be passed to the constructors of other subobjects. For example, when defining stream classes I typically privately inherit from a virtual base containing the stream buffer:
struct somebuf_base {
somebuf sbuf;
// ...
};
class somestream
: private virtual somebuf_base
, public std::ostream
{
public:
somestream(someargs)
: somebuf_base(someargs)
, std::ostream(&this->sbuf) {
}
// ...
};
Since base classes are constructed in the order they appear but virtual bases before non-virtual bases, the base class containing the sbuf member is constructed first. Its constructor replaces your Init() function.
When using C++ as of the 2011 revision, you might also use forwarding constructors to share logic between multiple constructors.
It's easier to take a pointer to ClassA; So, you can instantiate it whenever you want.(after the init())
If you used a pointer, don't forget to implement the virtual destructor and release the allocated memory for the ClassA *a
If you absolutely must call some function at the start of your constructor, and can't put that setup into some base class or early-constructed member, you could use this ugly trick:
ClassMain::ClassMain(int main_param)
: a( (Init(init_arg), class_a_arg1), class_a_arg2 )
{
}
In this case: No, we cannot avoid that.
The reason is that when calling Init or any other member function you are guaranteed by the language that the object you are in exists. As a is a member of ClassMain it must be constructed before any function in ClassMain can be called.
The only chance that you have here is to refactor the code.
I'm not an C++ expert and still do not have a great intuitive grasp of how things works. I think this is a simple question. I am having trouble passing objects with state to other objects. I'd prefer to avoid passing pointers or references, since once the initialized objects are setup, I call them millions of times in a tight loop. I think I'm dong something like a Command pattern. Here's the core of the problem. My header code is something like:
class ObjectWithState {
public:
ObjectWithState(int state) { // This constructor creates the problem!
state_ = state; // everyting works with no constructor.
}
private:
int state_;
};
class TakesObject {
public:
TakesObject(ObjectWithState obj) {
obj_ = obj;
}
private:
ObjectWithState obj_;
};
My main() functions looks like:
int main () {
ObjectWithState some_object(1);
TakesObject takes_object(some_object);
return 0
}
I get the following error (g++):
test.h: In constructor 'TakesObject::TakesObject(ObjectWithState)':
test.h:14: error: no matching function for call to 'ObjectWithState::ObjectWithState()'
test.h:5: note: candidates are: ObjectWithState::ObjectWithState(int)
test.h:3: note: ObjectWithState::ObjectWithState(const ObjectWithState&)
Simple answer?
I not sure if this has to do with copy constructors. If so, I'm trying to find a solution that keeps the class definition of ObjectWithState very clean and short. Users of this library will be defining lots of small functions like that which will be used by TakesObject function. Ideally programmers of the ObjectsWithState just need to focus on implementing a simple object. Perhaps I'm going astray...
What you may want to do is use the member initialisation syntax:
class TakesObject {
public:
TakesObject(ObjectWithState obj): obj_(obj) {
}
private:
ObjectWithState obj_;
};
In your posted code, the TakesObject constructor will first try to construct a new ObjectWithState with its default constructor, then call the assignment operator to copy the passed-in obj to obj_. The above example constructs the obj_ directly using its copy constructor.
You will also need to define a copy constructor for your ObjectWithState class, too:
class ObjectWithState {
public:
ObjectWithState(int state) {
state_ = state;
}
ObjectWithState(const ObjectWithState &rhs) {
state_ = rhs.state_;
}
private:
int state_;
};
If you omit all constructors from your class declaration, then the compiler supplies a default and a copy constructor for you. If you declare any constructors, then the compiler supplies no default or copy constructor, so you must implement your own.
You're getting this error because you're declaring a constructor. The compiler will provide the default constructor only if you don't declare a constructor in your class. Because you have declared a constructor, you don't get the default one. You have to explicitly declare a constructor with no parameters.