Similar questions have been answered but I still cannot find a solution to my problem. I am indeed not able to call the constructor of class Point inside class Rectangle. After having read some answers, I would approximately do it like this, but it does not work:
class Point {
public:
Point(int x, int y);
private:
int x;
int y;
};
Point::Point(int xx, int yy) {
x = xx;
y = yy;
}
class Rectangle {
public:
Rectangle(Point a, Point b) : Point(int x, int y); // this is wrong
private:
Point a;
Point b;
};
Rectangle::Rectangle(Point aa, Point bb) : Point(int x, int y) { // same as above
?
}
Can anyone help me to understand how to implement and fix this code (I know that declaring Rectangle as a struct makes it way easier)?
It is not clear what you expected this line to do:
Rectangle(Point a, Point b) : Point(int x, int y);
The place to initialize members is not the constructors body. And the correct syntax for the member initiazer list is:
Rectangle(Point a, Point b) : a(a), b(b) {}
Note that the initializer list is a place where shadowing is not an issue, you can use the same name for parameter and member, because there is no ambiguity. a(a) initializes the member a with parameter a.
Note that also constructor of Point should be:
Point::Point(int xx, int yy) : x(xx),y(yy) {
}
For int members it won't make a huge difference, but for class types it does make a huge difference: Members are initialzed before the body of the constructor runs. Fist initializing and then assigning in the constructor is inefficient and sometimes just wrong. On the other hand, there is no reason to not use the initializer list when the members are ints.
PS
(I know that declaring Rectangle as a struct makes it way easier)?
I think you refer to members being public in the struct. However, struct and class are just two different keywords to declare a class. The only difference is default access (see here for details: When should you use a class vs a struct in C++?) and those two definitions are identical:
class foo {
int a;
public:
int b;
};
struct foo {
private:
int a;
public:
int b;
};
Related
Is there a way to inherit private constructors with the using statement?
I tried adding a friend statement, but it did not seem to work.
struct B;
struct A
{
private:
A(int x) {}
A(int y, double z) {}
friend struct B;
};
struct B : public A
{
public:
using A::A;
//B(int x) : A(x) {}
//B(int x, int y) : A(x, y) {}
};
void demo()
{
B b1(5); // does not compile - implicit constructor is not accessible
B b2(4, 9.0);
}
I wonder if there is any way to do it with using, since if I explicitly create the delegating constructors the friend statement works, so this seams inconsistent:
struct B;
struct A
{
private:
A(int x) {}
A(int y, double z) {}
friend struct B;
};
struct B : public A
{
public:
B(int x) : A(x) {} // OK
B(int x, int y) : A(x, y) {}
};
void demo()
{
B b1(5); // OK
B b2(4, 9.0);
}
Accessibility of inherited constructors is not affected by the accessibility of the using declaration that introduces them.
[namespace.udecl] (emphasis mine)
19 A synonym created by a using-declaration has the usual
accessibility for a member-declaration. A using-declarator that names
a constructor does not create a synonym; instead, the additional
constructors are accessible if they would be accessible when used to
construct an object of the corresponding base class, and the
accessibility of the using-declaration is ignored.
Since you can't access the constructor of A in main, it isn't accessible to construct a B in main either (you would be able to use it in order to construct B's and A's inside the scope of B though, on account of the friendship). You'll need to spell out some sort of of forwarding c'tor explicitly for outside-the-class access. Since you seem to be after a "catch-all", a fairly simple solution can be
template<typename... Args>
B(Args&&... args) : A(std::forward<Args>(args)...) {}
I wonder if there is any way to do it with using, since if I explicitly create the delegating constructors the friend statement works
No, when using the base class constructors, they will keep the original protected or private access, so you need to implement them in the derived class if you'd like to make them public. Making B a friend doesn't change that. It only allows B to access the private members in A - both functions and variables.
If you'd like derived classes to be able to use certain private member functions, you usually make those member functions protected instead.
struct A {
protected:
A(int x) {}
A(int y, double z) {}
};
struct B : public A {
public:
B(int x) : A(x) {}
B(int y, double z) : A(y, z) {}
};
With this, you don't need to know about the derived classes when designing A and you also keep your private member variables in A private.
Based on #StoryTeller - Unslander Monica's answer, which explains that the (inherited) constructors are accessible where the base class constructors would be, here is a very partial solution which will work in some cases:
struct A
{
private:
A(int x) {};
A(int y, double z) {};
friend struct B;
};
struct B : public A
{
public:
friend void demo();
using A::A;
};
void demo()
{
B b1(5);
B b2(4, 9.0);
}
int main() {
demo();
}
If I have class A that declares Class B and instantiates an array of it.
class A{
class B{
int x, y;
};
B arrB[10];
public:
A();
};
Then, my issue is that I would like to initialize the first two objects of "arrB" in Class A using initialization list:
A::A(): arrB[0](1, 2), arrB[1](3, 4) {}
But the compiler does not accept it.
Can I initialize specific objects of the array or not? If yes, how to do it?
Thanks
The problem is that B hides its members by default as private because it is a class. Declare B a struct, or expose int x, y as public to be able to use aggregate initialization:
class A{
class B{
public:
int x, y;
};
B arrB[10] = {{1,2}};
public:
A();
};
The second problem is that you're not using aggregate initialization properly.
A::A(): arrB[0](1, 2), arrB[1](3, 4) {}
Should be
A::A(): arrB{{1, 2}, {3, 4}} {}
Demo
In order to initialize an array in the class member initialization list you need to use curly braces like you would if you were initializing an array in a function.
Thus if you wanted to initialize the first and second element of the array you would need to use at least
A() : arrB{{1,2}, {3,4}} {}
as the first set ({1,2}) says make arrB[0] a B with x and y initialized to 1 and 2 respectively. The second set ({3,4}) says make arrB[1] a B with x and y initialized to 3 and 4 respectively.
You do have to do one thing though in order to make this work. You either need to make B and aggregate by making x and y public, or you can provide a constructor for B that takes to values. Doing that lets you have either
class A{
class B{
public:
int x, y;
};
B arrB[10];
public:
A() : arrB{{}, {3,4}} {}
};
int main() {
A a;
}
or
class A{
class B{
int x, y;
public:
B() : x(), y() {} // need this so default instances are value initialized (zeroed in this case)
B(int x, int y) : x(x), y(y) {}
};
B arrB[10];
public:
A() : arrB{{}, {3,4}} {}
};
int main() {
A a;
}
I am learning about initializer list and learnt that const members must be initialized using it, because you cannot initialize it using default constructor or parameterised constructor.
class Foo
{
private:
const int y;
public:
Foo(int yy) :y(yy){}
int getY();
};
Now suppose if I have another member int x; not a const,Why can't I initialize it using default constructor, What is the idea behind this restriction?
The code that gives error:
class Foo
{
private:
const int y;
int x;
public:
Foo(int yy) :y(yy){}
Foo()
{
x = 100;
}
int getY();
};
I am learning about initializer list and learnt that const members must be initialized using it, because you cannot initialize it using default constructor or parameterised constructor.
Const members can be initialized in the member initializer list of both a default constructor and any parametrised constructor. (A default constructor is a constructor that can be invoked without parameters.)
Now suppose if I have another member int x; not a const,Why can't I initialize it using default constructor, What is the idea behind this restriction?
You can initialize any number of members (there is probably some implementation defined limit, but it's not relevant to this question) in the default constructor. There is no such restriction that you describe.
Demo, class with two members, both initialized in the default constructor:
struct Foo {
const int y;
int x;
Foo(): y(1), x(100){}
};
Edit for the mcve.
The code that gives error:
class Foo
{
private:
const int y;
int x;
public:
Foo(int yy) :y(yy){}
Foo()
{
x = 100;
}
int getY();
};
All constructors must initialize const members. Your parametrised constructor does initialize y, but the default constructor doesn't. That is why it doesn't work. See my demo above for a working example.
PS. Your parametrised constructor doesn't initialize x, but that is OK: x isn't const, so you can assign a value to it later.
In my code if I have a parameterised constructor like Foo(int xx) { x = xx;}
It will not give any error
This program:
struct Foo {
const int y;
int x;
Foo(int xx) { x = xx;}
};
Is ill formed in standard C++. If your compiler accepts it without a warning, then it isn't standard compliant.
Unclear what you're trying to accomplish.
Following code simply compiles
class Foo
{
private:
int _nonConst;
const int _const;
public:
Foo() : _const(10), _nonConst(11)
{
}
Foo(int x) : _const(x), _nonConst(x)
{
}
};
I am not sure I understood the question properly. To summarize what you can and can't do:
// .h
class MyClass
{
private:
int x;
const int y;
public:
MyClass();
MyClass(int initValue);
};
// .cpp
// The following is legal
MyClass::MyClass()
: x(0), y(0)
{}
// Alternatively, the following is legal too.
MyClass::MyClass()
: y(0)
{
x = 0;
}
// This is not legal: y cannot be initialized that way as it is const.
// No problem for x though.
MyClass::MyClass()
{
x = 0;
y = 0; // You cannot do that
}
// The following is legal
MyClass::MyClass(int initValue)
: x(initValue), y(initValue)
{}
// Alternatively, the following is legal too.
MyClass::MyClass(int initValue)
: y(initValue)
{
x = initValue;
}
// This is not legal: y cannot be initialized that way as it is const.
// No problem for x though.
MyClass::MyClass(int initValue)
{
x = initValue;
y = initValue; // You cannot do that
}
Of course, you can only have one CTor per declared signature. The examples above are 3 alternatives - 2 legal and 1 illegal - per declared signature.
From my understanding the following code will execute in this order:
Derived constructor is called.
Base object is constructed using the default base constructor.
Body of the derived constructor executes.
If so, isn't the member z is assigned a value twice?
class base {
public:
int x, y, z;
base() {x = 0; y = 0; z = 0;};
};
class derived : public base {
public:
derived() {z = 5;};
};
Is there a more efficient way to create an object of class "derived" so it uses a different constructor, in this case, one that would only assign members x and y a value, leaving z to be assigned a value in derived()?
Yes, there is a more efficient way, but it will take more code (thus increasing the maintenance overhead).
class base {
public:
int x, y, z;
// Default constructor
base() {x = 0; y = 0; z = 0;};
// Constructor to be called if you want to override the z value
base(int zValue) { x=0; y=0; z=zValue; };
};
class derived : public base {
public:
derived() : base(5) {};
};
Yes, z is assigned twice in your example, just what it looks like.
To do what you're wanting, you could do something like this, which requires almost exactly the same amount of code (just moving some here and there):
class base {
public:
int x, y, z;
base(int z = 0) : x(), y(), z(z) { }
};
class derived : public base {
public:
derived() : base(5) { } // with this one, z is assigned 5 once
// or
derived() { } // z is assigned 0 once
};
Sure. Use what's called a ctor-initializer:
class base {
public:
int x, y, z;
base(int z = 0) : x(0), y(0), z(z) {};
};
class derived : public base {
public:
derived() : base(5) {}
};
The code after the : and before the first { in the constructor declaration is a ctor-initializer. (Some people call it an "initializer list", but ctor-initializer is what the C++ standard calls it.)
You should always use ctor-initializers whenever you can to initialize class members to some value. While it doesn't really matter for ints, initialization using ctor-initializers can be faster than default constructing class members then assignment.
Definitely, you can do that.
Use member-initialization-list as:
class base {
public:
int x, y, z;
base(int a, int b, int c) : x(a), y(b), z(c) {}
//^^^^^^^^^^^^^^^^^^^ it's member-initialization-list!
};
class derived : public base {
public:
derived() : base(0,0,5) {}
// ^^^^^^^^^^^ call the specific base constructor
};
To elaborate on Andrew's answer, if you wanted to really make sure that all of base's members were set only once, and in the most efficient way possible, you could use a member-list initializer rather than setting values in the constructor.
class base {
public:
int x, y, z;
base() : x(0), y(0), z(0) {};
base( int xval, int yval, int zval ) :
x(xval), y(yval), z(zval)
{ };
};
class derived : public base {
public:
derived() : base( 0, 0, 5 ) {};
};
Most compilers will generate the same code for : x(_x), ... as just setting the values in the constructor, but I've seen a couple that did not.
In C++ I have a reference to an object that wants to point back to its owner, but I can't set the pointer during the containing class' construction because its not done constructing. So I'm trying to do something like this:
class A {
public:
A() : b(this) {}
private:
B b;
};
class B {
public:
B(A* _a) : a(_a) {}
private:
A* a;
};
Is there a way to ensure B always gets initialized with an A* without A holding a pointer to B?
Thanks
Try this:
class A;
class B {
public:
B(A *_a) : a(_a) {};
private:
A* a;
};
class A {
public:
A() : b(this) {};
private:
B b;
};
Since B is contained completely in A, it must be declared first. It needs a pointer to A, so you have to forward-declare A before you declare B.
This code compiles under more-or-less current versions of g++.
In C++ I have a reference to an object that wants to point back to its owner, but I can't set the pointer during the containing class' construction because its not done constructing.
You can store the pointer alright.
What you can't do is to try to get to the members/methods of A through the pointer in the constructor of B, since the parent instance might not be fully initialized at the point:
#include <iostream>
class Y;
class X
{
Y* y;
public:
X(Y* y);
};
class Y
{
X x;
int n;
public:
Y(): x(this), n(42) {}
int get_n() const { return n; }
};
X::X(Y* p): y(p)
{
//Now this is illegal:
//as it is, the n member has not been initialized yet for parent
//and hence get_n will return garbage
std::cout << p->get_n() << '\n';
}
int main()
{
Y y;
}
If you were to switch around the members in Y, so n would get initialized first, the constructor of X would print 42, but that is too fragile to depend on.