I have a class, it names A and A class has 3 another class in its private.
class A{
public:
A();
A(int num);
A(C& mC, P& mP, M& mM, int num);
//there is a getter and setter for all member this only one example(please check are they right?)
M getM()const{return pM;}
void setM(M classM){ pM = classM ;}
private:
C& pC;
P& pP;
M& pM;
int digit= 0;
};
I'm doing that in parameter constucture:
A::A(C& mC, P& mP, M& mM, int num):pC(mc),pP(mP),pM(mM)
{
// doing someting here
}
But I can't write a code for default and first parameter constructure, when I write something compiler saying to me that :
error: uninitialized reference member in ‘class A&’ [-fpermissive]
A::A(){
and
note: ‘A& A::pP’ should be initialized
A& pP;
someting like this, several errors and notes.
What should I do? How can I initialize classes in default and first parameter constructure?
Class A contains references to other object. Unlike pointers, references cannot be null. To make this work, you either need to:
Use pointers instead of references, and initialize them to nullptr is no valid object is provided in the constructor
Store those members by value. This involves a copy of the original arguments, and different in semantics - might not be what you need.
Related
I have const on the Accelerate method, yet I can call the power method. Is their a way to actually stop this.
class Engine{
public:
void Power(){
}
};
class Car{
public:
Car() : p(new Engine()){}
void Accelerator() const{
p->Power();
}
private:
Engine* p;
};
For Car, a const method is a methods which does not modify Car member variables.
so, as long that Car::Accelerator does not make p point to a different location, it is valid.
since p is not modified in Accelerator (meaning it does not point to a different memory address), the program is valid.
the moment you make p point to a different location, the program fails to compile:
void Accelerator() const {
p= nullptr; //wrong
}
Const protection affects only the direct members, in this case the pointer only. Values outside this object (aka. pointed values) are not protected.
You have to decide if you consider the pointed value as yourself or someone else.
You can modify the member Engine as const*, which will make the Engine object pointed to by p in Car const:
class Engine{
public:
void Power(){
}
};
class Car{
public:
Car() : p(new Engine()){}
void Accelerator() const{
p->Power();
}
private:
Engine const* p;
};
This will no longer compile:
test_const.cpp:12:9: error: member function 'Power' not viable: 'this' argument
has type 'const Engine', but function is not marked const
p->Power();
^
test_const.cpp:3:10: note: 'Power' declared here
void Power(){
^
But this implies that no member of Car can modify *p, which is probably not what you intend. See #NathanOliver's comment for better answer.
Hope this helps.
When I call a constructor which assigns a passed const & to a const & member variable, what happens? Since a const ref, my understanding is 'very little' - no copies, moves, constructors called, etc - just the copying of something likely to turn out to be a pointer.
E.g.
class ClassA
{
public:
ClassA(const double a):a_(a){}
const double a_;
};
class ClassB
{
const ClassA &classRef_;
public:
ClassB(const ClassA& a):classRef_(a){}
};
int main()
{
ClassA aObj(5.212);
ClassB bObj(aObj);
}
In particular, if I want to declare functions (such as here, the constructor) of ClassB as noexcept, what (if anything )do I need to know about ClassA?
In
int i;
int &r = i;
r = i is not an assignment, it is an initialisation. A reference act like an "alias": r will act like i.
You cannot assign references, only their referent:
r = 2; // same as i = 2
Here:
class ClassB
{
const ClassA &classRef_;
public:
ClassB(const ClassA& a):classRef_(a){}
};
In the constructor, the expression a designates a ClassA object (with a constant lvalue).
:classRef_(a) means "initialise the member reference classRef_ so that it becomes an alias for the object designated by a".
The new reference classRef_ will refer to the same object as the a reference. There is no copying.
I believe below should be noexcept safe on the assignment; I don't believe you can guarantee the reference is still "valid" after assignment, but the assignment should be safe. You may want to use a weak_ptr here if you're concerned about the reference being invalidated. The member initialization is a reference assignment (or copy depending on how you look at it). If the reference is borked, you can still copy the reference.
class ClassB
{
const ClassA &classRef_;
public:
ClassB(const ClassA& a):classRef_(a){}
};
In order to make the below noexcept, you should make the copy constructor nothrow as well; probably use std::swap(a,b):
class ClassA
{
public:
ClassA(const double a):a_(a){}
const double a_;
};
I cannot find this question even being asked anywhere...so that makes me believe i'm doing something very wrong here...
Lets say I have a base class, A, with a constructor that takes in int parameter.
In my derived class, B, I wish to invoke that constructor but also initialize a member reference passed in B's constructor. How can i do this? I cannot find the syntax to add an initialization list if I call the base class constructor. Is this possible?
Lets say I have:
Class Object
{
Object(){}
}
Class A
{
A(int number) : m_number(number){}
public:
int m_number;
}
Now, how would I initialize m_obj if i wish to call the non-default constructor of A?
e.g.
Class B : Class A
{
B(int number, const Object& objRef) : A(number)
{
m_obj = objRef; //error, : must be initialized in constructor base/member
// initializer list...but I cannot access an initializer list!!
}
private:
const Object& m_obj;
}
as I said, my intent is probably all wrong here, but if it's valid, I cannot find any syntax examples on google..
go easy on me...:)
In the constructor's initialization-list:
B(int number, const Object& objRef) : A(number), m_obj(objRef)
{}
(Note, this is nothing to do with this being a subclass. You always need to use the initialization list in order to initialize a member variable that's a reference.)
I have three classes; their function definitions are in a sperate file.
I'm trying to construct an object with various parameters inside another class without using inline implementation.
class A{
public:
A(){}
};
class B{
public:
//takes in two ints, one reference to object, and a string
B(int x, int y, A &a, std::string s );
};
class C{
public:
//in the constructor, construct b_obj with its parameters
C();
private:
B b_obj;
};
How can I make the C constructor construct b_obj with its parameters of the int, the reference to an instance of A, and the string? I tried some methods but I get an error that complains about no match call to the b_obj constructor.
Use an initializer:
C() : b_obj(5, 6, A(), ""){}
This line technically won't work, though, because B's constructor takes an A&, so you can't bind a temporary to it. const A & if it's not being changed, or A if it is, would work out better if you don't have a non-temporary A to pass in.
You need to pass the relevant items to a constructor of object C, and then use an initializer.
class C {
public:
C(int x, int y, A& a, std::string s) : b_obj(x, y, a, s) {}
Internally and about the generated code, is there a really difference between :
MyClass::MyClass(): _capacity(15), _data(NULL), _len(0)
{
}
and
MyClass::MyClass()
{
_capacity=15;
_data=NULL;
_len=0
}
thanks...
You need to use initialization list to initialize constant members,references and base class
When you need to initialize constant member, references and pass parameters to base class constructors, as mentioned in comments, you need to use initialization list.
struct aa
{
int i;
const int ci; // constant member
aa() : i(0) {} // will fail, constant member not initialized
};
struct aa
{
int i;
const int ci;
aa() : i(0) { ci = 3;} // will fail, ci is constant
};
struct aa
{
int i;
const int ci;
aa() : i(0), ci(3) {} // works
};
Example (non exhaustive) class/struct contains reference:
struct bb {};
struct aa
{
bb& rb;
aa(bb& b ) : rb(b) {}
};
// usage:
bb b;
aa a(b);
And example of initializing base class that requires a parameter (e.g. no default constructor):
struct bb {};
struct dd
{
char c;
dd(char x) : c(x) {}
};
struct aa : dd
{
bb& rb;
aa(bb& b ) : dd('a'), rb(b) {}
};
Assuming that those values are primitive types, then no, there's no difference. Initialization lists only make a difference when you have objects as members, since instead of using default initialization followed by assignment, the initialization list lets you initialize the object to its final value. This can actually be noticeably faster.
Yes. In the first case you can declare _capacity, _data and _len as constants:
class MyClass
{
private:
const int _capacity;
const void *_data;
const int _len;
// ...
};
This would be important if you want to ensure const-ness of these instance variables while computing their values at runtime, for example:
MyClass::MyClass() :
_capacity(someMethod()),
_data(someOtherMethod()),
_len(yetAnotherMethod())
{
}
const instances must be initialized in the initializer list or the underlying types must provide public parameterless constructors (which primitive types do).
I think this link http://www.cplusplus.com/forum/articles/17820/ gives an excellent explanation - especially for those new to C++.
The reason why intialiser lists are more efficient is that within the constructor body, only assignments take place, not initialisation. So if you are dealing with a non-built-in type, the default constructor for that object has already been called before the body of the constructor has been entered. Inside the constructor body, you are assigning a value to that object.
In effect, this is a call to the default constructor followed by a call to the copy-assignment operator. The initialiser list allows you to call the copy constructor directly, and this can sometimes be significantly faster (recall that the initialiser list is before the body of the constructor)
I'll add that if you have members of class type with no default constructor available, initialization is the only way to construct your class.
A big difference is that the assignment can initialize members of a parent class; the initializer only works on members declared at the current class scope.
Depends on the types involved. The difference is similar between
std::string a;
a = "hai";
and
std::string a("hai");
where the second form is initialization list- that is, it makes a difference if the type requires constructor arguments or is more efficient with constructor arguments.
The real difference boils down to how the gcc compiler generate machine code and lay down the memory. Explain:
(phase1) Before the init body (including the init list): the compiler allocate required memory for the class. The class is alive already!
(phase2) In the init body: since the memory is allocated, every assignment now indicates an operation on the already exiting/'initialized' variable.
There are certainly other ways to handle const type members. But to ease their life, the gcc compiler writers decide to set up some rules
const type members must be initialized before the init body.
After phase1, any write operation only valid for non-constant members.
There is only one way to initialize base class instances and non-static member variables and that is using the initializer list.
If you don't specify a base or non-static member variable in your constructor's initializer list then that member or base will either be default-initialized (if the member/base is a non-POD class type or array of non-POD class types) or left uninitialized otherwise.
Once the constructor body is entered, all bases or members will have been initialized or left uninitialized (i.e. they will have an indeterminate value). There is no opportunity in the constructor body to influence how they should be initialized.
You may be able to assign new values to members in the constructor body but it is not possible to assign to const members or members of class type which have been made non-assignable and it is not possible to rebind references.
For built in types and some user-defined types, assigning in the constructor body may have exactly the same effect as initializing with the same value in the initializer list.
If you fail to name a member or base in an initializer list and that entity is a reference, has class type with no accessible user-declared default constructor, is const qualified and has POD type or is a POD class type or array of POD class type containing a const qualified member (directly or indirectly) then the program is ill-formed.
If you write an initializer list, you do all in one step; if you don't write an initilizer list, you'll do 2 steps: one for declaration and one for asign the value.
There is a difference between initialization list and initialization statement in a constructor.
Let's consider below code:
#include <initializer_list>
#include <iostream>
#include <algorithm>
#include <numeric>
class MyBase {
public:
MyBase() {
std::cout << __FUNCTION__ << std::endl;
}
};
class MyClass : public MyBase {
public:
MyClass::MyClass() : _capacity( 15 ), _data( NULL ), _len( 0 ) {
std::cout << __FUNCTION__ << std::endl;
}
private:
int _capacity;
int* _data;
int _len;
};
class MyClass2 : public MyBase {
public:
MyClass2::MyClass2() {
std::cout << __FUNCTION__ << std::endl;
_capacity = 15;
_data = NULL;
_len = 0;
}
private:
int _capacity;
int* _data;
int _len;
};
int main() {
MyClass c;
MyClass2 d;
return 0;
}
When MyClass is used, all the members will be initialized before the first statement in a constructor executed.
But, when MyClass2 is used, all the members are not initialized when the first statement in a constructor executed.
In later case, there may be regression problem when someone added some code in a constructor before a certain member is initialized.
Here is a point that I did not see others refer to it:
class temp{
public:
temp(int var);
};
The temp class does not have a default ctor. When we use it in another class as follow:
class mainClass{
public:
mainClass(){}
private:
int a;
temp obj;
};
the code will not compile, cause the compiler does not know how to initialize obj, cause it has just an explicit ctor which receives an int value, so we have to change the ctor as follow:
mainClass(int sth):obj(sth){}
So, it is not just about const and references!