Composition of classes - c++

How come, when setting up class composition, contained classes can be called with a default constructor but not with one that takes parameters?
That's kind of confusing; let me offer an example.
#include "A.h"
class B
{
private:
A legal; // this kind of composition is allowed
A illegal(2,2); // this kind is not.
};
Assuming both the default constructor and one that takes 2 integers exists, only one of these is allowed. Why is this?

It is allowed for sure, but you just need to write it differently. You need to use the initializer list for the composite class's constructor:
#include "A.h"
class B
{
private:
A legal; // this kind of composition is allowed
A illegal; // this kind is, too
public:
B();
};
B::B() :
legal(), // optional, because this is the default
illegal(2, 2) // now legal
{
}

You can provide constructor parameters, but you are initialising your members wrong.
#include "A.h"
class B
{
private:
int x = 3; // you can't do this, either
A a(2,2);
};
Here's your solution, the ctor-initializer:
#include "A.h"
class B
{
public:
B() : x(3), a(2,2) {};
private:
int x;
A a;
};

a class declaration does NOT initialize the members which compose the class. hence, the error when you are trying to constrcut an object inside the declaration.
member initialization takes place inside the constructor of a class. so you should write:
#include "A.h"
class B
{
public:
B();
private:
A a;
};
B::B() :
a(2,2)
{
}

Related

Initilize constructor of class from another class

I have class A with constructor A(int a)
A.h
calss A{
public : A(int a);
}
A.cpp
#include "a.h"
#include <iostream>
A::A(int a)
{
std::cout<<a<<end;
}
I need to initialize this class from another class B,
I tried
B.h
class B{
public : B();
A tmp;
//A tmp(4); //this giving syntax error
}
and
B.cpp
B(){
tmp = A(4);
}
But I am getting compiler error "error: no matching function for call to 'A::A()'"
The problem is that A doesn't have a default constructor (because if you define another constructor and default one is not generated) and so A objects cannot be default constructed.
The solution is to use constructor initialization lists for every constructor of B where you call the appropriate constructor for tmp.
class B {
A tmp;
public:
B() : tmp(4) {}
};
If you can use c++11 and in every (or at least most of the) constructors of B you create tmp the same way you can use:
class B {
A tmp{4};
public:
B() {};
}
Constructors should not have a return type. Remove the void in the declaration and you should be good to go. Same goes for your class B.
Constructors are special member functions without any return type.
//A tmp(4); //this giving syntax error
This will for sure give you an error because you mentioned
void A(int a)
and this is not constructor; because its has return type (void).
when you explicitly define parametrized constructor (like A(int a) )the default constructor gets vanished and for this statement
A tmp;
to compile you have to provide your own default constructor.
It would be great always to post complete error message.
Rather than getting "no matching function for call to" , I am sure that you will be getting below error:
error: no matching function for call to ‘A::A()’
note: A::A(int)
This clearly indicates that default constructor A::A() is missing from your code as you have provided your own constructor.
Suggestion: You have defined conversion constructor. It is good practice to use "explicit" keyword.
*.h file
class A
{
public:
A(int a);
};
class B
{
public:
B();
A *tmpA;
};
*.cpp file
A::A(int a)
{
MessageBox(NULL,L"",L"", MB_OK);
}
B::B()
{
tmpA = new A(4);
}
usage
{
B *b = new B();
}
is it correct for you?

C++03 Resolve a circle composition when calling a member function

I've got the following class structure. This obviously won't compile. I can forward declare B. Then, I can either use function pointers in function calls but it's not a nice solution, as I would call other other functions in A from A::funcA or put part of the declaration of B into a header, which would be a few hundreds of lines and would be practical.
What (else) would be the preferred way to handle this situation?
class B;
class A
{
public:
void funcA(B* b);
double funcA2();
int funcA4(B* b);
private:
E memberA1;
E memberA2;
};
void A::funcA( B* b) {
b->funcB(a->memberA1, a->memberA2);
class B : public BBase
{
public:
void FuncB(E* e1, E* e2)
{
/* using const objects of B that are initialized
by B() and some other functions... */
}
std::vector<C*> memberB1; // C has std::vector<A*> memberC1
};
int main() {
calling B->memberB1.at(0)->memberC1.at(0)->funcA();
}
I have the the following (omitting some unneccesary lines):
A.h
Class B;
Class A {
declaration of A
};
A.cpp ....
B.h
#include "A.h"
#include "BBase.h"
Class B {
declaration of B
};
B.cpp ....
BBase.h
#include "C.h"
#include "A.h"
#include "AInterface.h"
typedef std::vector<AInterface> AList;
BBase {
declaration of abstract BBase
};
BBase.cpp ....`
But I still get error: member access into incomplete type 'B'.
Assuming E and C are adequately declared/defined, then what you have is almost fine. The problem is that you define the member function of A before you have the definition of the B class, make sure that class B is fully defined (the actual class, not the full implementation of its member functions) before you you have the A member functions implemented.
So something like this:
class B;
class A { ...; void member_function(B*); ... };
class B { ...; void other_member_function(); ... };
void A::member_function(B* b) { ...; b->other_member_function(); ... }
I would suggest to use either the Interface instead of concrete B class
class B : public IB{
};
and pass IB instead of B to A.
either even better in c++ use a template function and bind your member function which you want to call
a.funcA( std::bind( &B::funcB, &b, someArg );

Initialize an array inside Constructor in C++

I have defined an array within a class. I want to initialize the array with some values pre-decided value. If I could do it in definition only then it will be easier as I would have used
class A{
int array[7]={2,3,4,1,6,5,4};
}
But, I can't do that. This, I need to do inside Constructor. But I can't use the same above syntax as it would create a new array inside Constructor and won't affect the array defined in class. What can be the easiest way to do it?
class A{
public:
int array[7];
A::A(){
}
}
You can initialize the array in the constructor member initializer list
A::A() : array{2,3,4,1,6,5,4} {
}
or for older syntax
A::A() : array({2,3,4,1,6,5,4}) {
}
Your sample should compile, using a compiler supporting the latest standard though.
Also note your class declaration is missing a trailing semicolon
class A{
public:
int array[7];
A();
};
// ^
With C++11 you can write this:
class C
{
int x[4];
public:
C() : x{0,1,2,3}
{
// Ctor
}
};

Do we "inherit" constructors in C++ ? What's is exact definition of "inheriting"

I wonder why people say:
"Inheriting class doesn't inherit the constructor".
If you could CAN use the parent class' constructor, and the parameterless constructor are called automatically no matter what.
Example:
#include <iostream>
using namespace std;
class A {
private :
int x;
public :
A () {
cout << "I anyway use parameter-less constructors, they are called always" << endl;
}
A (const int& x) {
this->x = x;
cout << "I can use the parent constructor" << endl;
}
};
class B : public A {
private :
int y;
public :
B() {
}
B (const int& x, const int& y) : A (x) {
this->y = y;
}
};
int main() {
B* b = new B(1,2);
B* b1 = new B();
return 0;
}
http://ideone.com/e.js/6jzkiP
So is it correct to 'say', constructors are inherited in c++ ? What is exact definition of "inherit" in programming languages ?
Thanks in advance.
I wonder why people say: "Inheriting class doesn't inherit the constructor".
Perhaps it is best to illustrate this with an example:
struct Foo
{
Foo(int, int) {}
};
struct Bar : Foo
{
};
What it means is that there is no Bar::Bar(int, int) constructor that you can call, despite the existence of a constructor with the same parameter list in the base class. So you cannot do this:
Bar b(42, 42);
In C++11, you can actually inherit constructors, but you must be explicit about it:
struct Bar : Foo
{
using Foo::Foo;
};
Now, you can say Bar b(42, 42);
What they mean is that constructor signatures are not inherited.
In your example, B does not have a constructor taking a single const int& even though its base class does. In this sense it has not "inherited" the constructor (but can still make use of it).
I think what they mean is:
struct A {
A(int, int) { }
};
struct B : public A {
};
int main()
{
A a(1, 2); // ok
B b(1, 2); // error
}
To compare with “non-special” member functions:
struct A {
void f() { }
};
struct B : public A {
};
int main()
{
A a;
B b;
a.f(); // ok
b.f(); // ok too
}
But of course, from within B you can call accessible A constructors (as automatically generated ones do). Ditto for the destructor.
Note that in C++11 you can use the “inheriting constructors” feature:
struct A {
A(int, int) { }
};
struct B : public A {
using A::A;
};
int main()
{
A a(1, 2); // ok
B b(1, 2); // ok now
}
A derived class can/must see base class constructors in order to invoke them, for consistency. However, their signature is not exposed in the derived class, hence, one cannot construct the class without an explicitly defined constructor, which forwards the required arguments to the base class constructor.
In C++11, one can inherit constructors: What is constructor inheritance?
Another approach to circumvent 'proxy constructors' in C++ < 11: How to define different types for the same class in C++
In your example, the default ("parameterless" as you say) constructor of B does invoke the default constructor of A, but this does not mean that B "inherited" that constructor, only that it "has access to" it. That is, A's default constructor is accessible from within B, yet it is not accessible from outside (no one can use A's default constructor from outside to construct an instance of B).
Another way to look at it is to ask, what is something frustrating about constructors and inheritance in C++? A common answer from some people (including myself) would be that there is no automatic facility which allows "pass-through" construction of base classes taking arguments from derived class constructors without explicitly declaring and defining the latter.

c++ how to write a constructor?

I'm not used to c++ and I'm having a problem writing a constructor.
See this example, is a short version of the code I'm working on:
class B {
public:
B(int x);
}
class A {
public:
B b;
A(){
// here I have to initialize b
}
}
That throws a compiler error since I need to initialize b in A's constructor because B does not have a default constructor.
I think I have do it in the initialization list, but the B(int x) argument is a value I have to calculate with some algorithm, so I don't know how this should be properly done, or if I'm missing something or doing it wrong.
In other language like java I would have a reference to B and initialize it inside the A's constructor after the other code I need to get the value for the initialization.
What would be the right way to initialize b in this case?
Thanks!
You can invoke functions in your constructor initializer list
class B {
public:
B(int x);
}; // note semicolon
class A {
public:
B b;
A()
:b(calculateValue()) {
// here I have to initialize b
}
static int calculateValue() {
/* ... */
}
}; // note semicolon
Note that in the initializer list, the class is considered completely defined, so you can see members declared later on too. Also better not use non-static functions in the constructor initializer list, since not all members have yet been initialized at that point. A static member function call is fine.
You use an initializer list, something like this:
A() : b(f(x)) {}
#include<iostream>
class B {
public:
B(){} // A default constructor is a must, if you have other variations of constructor
B(int x){}
}; // class body ends with a semicolon
class A {
private:
B b;
public:
A(){
// here I have to initialize b
}
void write(){
std::cout<<"Awesome";
}
};
int main(){
A a;
a.write();
}
In C++, if you have a constructor that takes an argument, a default constructor is a must, unlike other languages as Java. That's all you need to change. Thanks.