Say we have a class A that contains as a member of the same class:
Class A{
const A &a;
}
I want to create a parametized constructor that passed the value of that member, but I do not want to define the copy constructor of the class.
A(const A& memberA): a(memberA) {}
How could indicate the compiler such thing?
Thanks
A constructor that can take just a reference to the class it constructs is a copy constructor, whether you want it to be one or not. Copy constructors are defined thus:
A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments.
You could declare it explicit to restrict how the class can be copied (preventing A a = A() for example), but it's still a copy constructor as long as it has that signature.
You can define this constructor as explicit.
(That's a good rule for all constructors that can be called with one parameter.)
Related
I have a class like this:
class A{
private:
init(const std::string& s=""){/*do something*/}
public:
A(){init();}
A(const A&){init();}
A(const std::string& s){init(s);}
};
Does it cover all the forms that constructors may be called?
What I am trying to do is, any object creation must call the init() function at first i.e I need to define all the constructors that may be called implicitly or explicitly.
A(const A&)
once you have defined A(A const&) the compiler will not synthesize any other constructors. The only callable constructors will be the ones you declare.
The same is true of A(A&&), as an aside.
It sounds like you have a slight misunderstanding of C++ constructors.
Under specific circumstances classes have certain constructors implicitly declared with defaulted definitions. To avoid constructors that don't call your init() function does not require you to declare these constructors. You can instead follow certain rules that prevent them from being implicitly declared, or you can define some in-class initialization which ensures that the default definitions do the extra initialization you want.
The default constructor is only implicitly declared as defaulted if there are no user-declared constructors.
A copy constructor is only implicitly declared as defaulted if there are no user-declared move constructors or move-assignment operators (and of course no user-declared copy constructor).
A move constructor is only implicitly declared if there are no user-declared copy constructors, copy assignment operators, move constructors, move assignment operators, or destructors (and if the default definition for a move constructor would be valid).
So you could ensure that object construction always calls your init() function by declaring some subset of members that suppresses implicit declarations of any other constructors.
(This slideshow has a handy reference on the conditions for implicit declarations of the special member functions.)
Following the above rules: Declaring this copy constructor, for example, suppresses the default constructor, the move constructor, and the implicitly declared copy constructor. This therefore ensures that no objects of this class can be constructed without calling the init() member function.
struct S {
S(S const &) { init(); }
void init() {}
};
You can also simply use C++11 in-class initialization, which executes even in default definitions, to ensure init() is called for all construction.
struct S {
int x = init();
int init() { return 10; }
// ... whatever constructors you want to define
};
So long as your user-declared constructors don't explicitly initialize x, then all the constructors, both user-declared and implicitly declared, will call init().
I have a hack that does this, but it isn't the most clear on intent.
class A{
private:
bool init(...){...; return true; }
bool initialized = init(...);
public:
// your constructors.
};
Do keep in mind that the parameters to init have not to be dependent on the parameters of the constructor.
For this case, it might be worth considering using implementation inheritance:
class base {
protected:
base(std::string const &s="") { /* equivalent of your `init` */ }
// Or possibly use overloading:
// base() { /* whatever */ }
// base(std::string const &) { /* whatever */ }
};
class A : public base {
A(const std::string& s) : base(s) {}
A(const A&, const std::string& s) : base(s) {}
};
Since A is derived from base, every ctor for A must invoke base's constructor. If you don't use the member initializer list to pass a parameter, it'll be invoked automatically with the default parameter--but creating an A without invoking the base ctor is essentially impossible.
I think you'd better define the move constructor A(A&&), I'm not sure about the policies on automatically generate constructor of different compilers, though C++11 has the explicit definition.
see more info here
I have a simple question:
class my
{
};
my ob;
Compiler allows me to create an object which makes sense. And, I am aware that you can't create object where the constructor is private.
To me it looks that, everything inside the class is private but obviously not the default constructor(because it is allowing me to create the object as default constructor should be public). But what confuses me is that there is no public section in the class.
So, does it create a public section only to put a default constructor under it in this case?
Or there is something else going on and my rationale is incorrect?
Also, how are accesses public, private and protected internally organised/tracked when an object is created/accessed?
I got this question as I never created an object of an empty class until now.
If you do not declare any constructor yourself, C++ compilers will always generate a public trivial constructor for you. More than that even, it will also implicitly create a public copy constructor and assignment operator.
From C++11 standard 12.1.5:
If
there is no user-declared constructor for class X, a constructor having no parameters is implicitly declared
as defaulted. An implicitly-declared default constructor is an inline public member of its class.
and 12.8.7, 12.8.11:
If the class definition does not explicitly declare a copy constructor, one is declared implicitly. [...] An implicitly-declared copy [...] constructor is an inline public member of its class.
and finally 12.8.18, 12.8.20, 12.8.22:
If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. [...] If the definition of a class X does not explicitly declare a move assignment operator, one will be implicitly
declared [...]. An implicitly-declared
copy/move assignment operator is an inline public member of its class.
Note that a move assignment operator will only be generated under certain circumstances, which are beyond the scope of this question, see 12.8.20 for more details.
If you want a private constructor you have to declare it yourself:
class my { my() {} };
If you want to prevent the generation of copy constructor or assignment operator you can either declare, but not implement them:
class my { my(my const &); };
Or, since C++11, explicitly delete them:
class my { my(my const &) = delete; };
Yes, the compiler will produce the default constructor and the default copy constructor and default assignment operators as "public" - because anything else would make the class rather useless...
Of course, those constructors would be rather simple - in fact, it can be replaced with "nothing", since constructing an empty class will do nothing.
The compiler generated default constructor (and other operators) are automatically public. If you want the default constructor to be private then you need to specify this yourself my declaring it within a private section of your class.
The concepts of private, protected and public are only relevant to the compiler. They have no meaning and are not tracked at runtime.
The compiler will generate the default constructor as inline public if it is not defined by the user, the relevant section of the C++ draft standard is 12.1/5:
If there is no user-declared constructor for class X, a constructor having no parameters is implicitly declared as defaulted (8.4). An implicitly-declared default constructor is an inline public member of its class.
Usually compiler by default generates 4 things at the time of creation of object.
Default constructor
Copy constructor
Copy assignment operator
Destructor
For example:
class First {
First(){} //default constructor
First(const First &){} //copy constructor
First& operator=(const First&){ //Copy assignment operator
return *this;
}
~First(){} //Destructor
}
These are implicitly inline public member, unless there is no user declared constructor.
Am I doing this right? This is a highly simplified version of my code:
class Logger {
public:
Logger(std::ostream) { /*...*/}
};
class Driver {
public:
Driver() : m_logger(std::cout) {}
Driver(Logger& logger) : m_logger(logger) {}
private
Logger m_logger;
};
So my class Driver has a member of type Logger. When I call the argument-less constructor Driver(), the instance of Driver creates its own instance of Logger using std::cout.
When calling Driver(Logger) the instance shall use an already existing instance of Logger passed as a reference.
The above code compiles using g++. Although I understand what happens when calling Driver(), I don't get what happens when calling Driver(Logger). Logger has no constructor which accepts a reference on Logger as argument ("copy constructor"). So what is executed when calling Driver(Logger)?
A trivial copy constructor for Logger is synthesised for you, unless you declare one yourself.
This is much the same as how a trivial default constructor is synthesised for you (if you don't declare a default user-defined constructor).
[C++11: 12.8/7]: If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor
is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor. Thus, for the class definition
struct X {
X(const X&, int);
};
a copy constructor is implicitly-declared. If the user-declared constructor is later defined as
X::X(const X& x, int i =0) { /* ... */ }
then any use of X’s copy constructor is ill-formed because of the ambiguity; no diagnostic is required.
[C++11: 12.8/8]: The implicitly-declared copy constructor for a class X will have the form
X::X(const X&)
if
each direct or virtual base class B of X has a copy constructor whose first parameter is of type const B& or const volatile B&, and
for all the non-static data members of X that are of a class type M (or array thereof), each such class type has a copy constructor whose first parameter is of type const M& or const volatile M&.
Otherwise, the implicitly-declared copy constructor will have the form
X::X(X&)
When you construct a Driver with a Logger argument, it is taken by reference and the Logger copy constructor is invoked to initialize m_logger, so you end up with a new Logger that is a copy of the argument. The copy constructor is provided by the compiler unless you explicitly make Logger non-copyable, by declaring the copy constructor private.
Seems perfectly valid, except that you should make the logger argument a const reference; you're going to copy it, after all, not modify it.
Consider this piece of code:
class complex{
private:
double re, im;
public:
complex(double _re, double _im):re(_re),im(_im){}
complex(complex c):re(c.re),im(c.im){}
};
I already knew that the copy constructor complex(complex c) will cause infinite recursion.
However, it should only pick const reference copy constructor complex(const complex &c) as the function for copying, since this is the default behavior if it is not explicitly specified. Every thing else is excluded, such as complex(complex c).
Why does it apply the function with pass by value here? Or both are copy constructors, except the pass by value cannot be modified and is used to pass to other functions rather than its constructor?
I think in Java, it is permitted to do like that, since it will just copy the object into the constructor.
A copy constructor must be in on of the following forms:
T(T&);
T(const T&);
That is, a constructor is a copy constructor only if it takes a single parameter of reference class type. A constructor that takes a single parameter of class type by-value is, by definition, not a copy constructor (edit) -- and in fact is illegal, as pointed out by Cat Plus Plus.
12.1 : Constructors
10/A copy constructor for a class X is a constructor with a first parameter of type X& or of type const X&
Beyond this Standardese, however, is a fundamental error in your understanding of the copy constructor. Consider the following code:
class Foo
{
public:
Foo() {}
Foo(Foo f) {/*...*/};
};
int main()
{
Foo f1;
Foo f2(f1);
}
When f2 is constructed f1 is passed by-value. In order to evaluate the parameters for the constructor call, f1 must be copied. So, you see there is a paradox here. In order to call the copy constructor, you must make a copy. In order to make a copy, you must call the copy constructor...
The above must call the constructor with an argument by-value simply because that is what the type of the parameter is: it's a Foo by-value. It it were not by-value, it would have to be either by reference, which looks like this:
Foo(Foo& rhs)
/* or like this: */ Foo(const Foo& rhs);
...or it must take it by pointer, which looks like this:
Foo(Foo* prhs)
...but, in the latter case, this is obviously not a copy constructor given the definition above.
complex(complex) is not a copy constructor. It's ill-formed, and should be rejected by compiler. There is no infinite recursion, because you simply cannot define a constructor like that.
A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments (8.3.6).
A declaration of a constructor for a class X is ill-formed if its first parameter is of type (optionally cv-qualified)
X and either there are no other parameters or else all other parameters have default arguments. A member
function template is never instantiated to produce such a constructor signature.
Answer to Java question since all other possible explanations are given:
//java code
public class Bar{
private int foo;
public Bar() { } // public no-args constructor
public Bar(Bar b) { foo = b.foo; } // copy constructor
}
In Java objects are references and not value objects like they are in C++. In C++ when you copy an object you create a copy of the object's state, internal variables etc. In Java it simply copies the reference. The object's state is not copied so there is actually no need to call the copy constructor like you do it in C++.
While learning the concept of "copying members", the book gives the following statement.
In addition, a default assignment cannot be generated if a nonstatic member is a reference, a const,or a user-defined type without a copy assignment.
I do not quite understand what does this statement really want to deliver? Or which kind of scenario does this statement refer to? Thanks.
This statement has to do with the compiler automatically generating the default assignment operator function for a class you write (i.e. user-defined type). The default assignment works by copying all the members over to a new instance. This statement covers three cases where a default assignment would not be able to be generated:
1) When a member is a reference (i.e. refers to an instance of a variable, like a pointer)
class Foop {
int& reference;
};
2) When a member variable is constant
class Foople {
const int someConst;
};
3) When some other class does not have a copy-constructor and you have a member variable of that type, obviously it cannot be copied using the default method (which uses copy-constructors)
class Uncopyable {
private:
Uncopyable(Uncopyable const& other);
};
class Fleep {
Uncopyable uncopyable;
};
In these cases, you would need to write your own assignment operator (or possibly do without).
If you have a member in your class which is not static (shared between all instances of class), and is either
a reference (high level pointer)
a constant
a user-defined type with dynamic data (the same as the class we're talking about)
The default = operator and copy constructor is no longer valid and you should write manual versions of those.
class ClassA
{
int& _myReferenceMember;
const int _myConstant;
ClassB _objWhereClassBHasNoCopyConstructor;
}
Above are examples of the three cases you described. And as you quoted, you must write a custom copy constructor (if you want a copy constructor at all) in such a case, or change your member variables.
It refers to the distinction between:
class A { int a; };
and
class B { int& a; };
For class A, the compiler will generate an implicit assignment operator (=), but in the case of B, it cannot. This is because references in C++ don't have pointer semantics. i.e. you cannot change what a reference point to after it is constructed, hence, the implicit copy constructor would not be able to copy that member. The same thing goes for const members (which are explicitly marked as being immutable) and members which don't have a assignment operators (implicit or explicit).
The default assignment operator for A would essentially do this:
class A
{
A& operator=(A const& a_) { a = a_.a; }
int a;
};