I have some understanding problems in C++ with parameterised constructors.
If I have a class with one constructor which have two function parameters, how can i instantiate it in an other class header file?
For example:
public:
MyFunction myfunction(param1, param2); //makes an error
How can i declare an object like this?
You need to write MyFunction myfunction; in the class declaration.
Then in the member initialiser list of the constructor to the class of which myfunction is a member, write
/*Your constructor here*/ : myfunction(param1, param2)
{
/*the constructor body*/
}
The bit after the colon is the member initialiser list. param1 and param2 are obviously arguments to that constructor.
You have several ways:
struct P
{
P(int a, int b) :a(a), b(b){}
int a;
int b;
};
struct S
{
S() : p1(4, 2) {} // initializer list
P p1;
P p2{4, 2}; // since c++11
P p3 = P(4, 2); // since c++11
};
An option is having a predeclaration and a pointer to the class.
classA.h
class A
{
public:
A(a,b);
};
classB.h
class A;
class B{
public:
A* foo;
B();
~B();
}
classB.cpp
#include classA.h
#include classB.h
B()
{
foo=new A(a,b);
}
~B()
{
delete(foo);
}
As far as I understand, the problem is that MyFunction has only one constructor that only accepts two arguments.
You can use a pointer to that object and then initialize it in the constructor:
#include <memory>
class Something {
public:
std::shared_ptr<MyFunction> data;
Something(int par1, int par2) {
data = std::shared_ptr<MyFunction>(new MyFunction(par1, par2)); // here you go!
}
~Something() {
//delete data; no need to do this now
}
};
Edit: added a smart pointer to follow rule of three.
Related
I have the following sample code
class ClassB {
public:
ClassB(int i); // No default constructor
}
class ClassA {
ClassB obj; //NOT a pointer
public
ClassA() {
//calculate someInt;
obj = ClassB(someInt); // doesnt work
}
}
How do I initialize obj?
The compiler complains about no appropriate default constructor available for obj
The best design solution for you would be to initialize member obj in the initialization list like this:
ClassA() : obj(someInt) { }
However, another option for you would be to declare the default constructor for ClassB like this:
ClassB() {}
or simply let the compiler create the one for you by using this:
ClassB() = default;
From C++ Standard this is:
defaulted default constructor: the compiler will define the implicit
default constructor even if other constructors are present.
If you go for a second option, then the following code would pass without the error:
#include <iostream>
class ClassB {
public:
ClassB() = default;
ClassB(int i);
};
class ClassA {
ClassB obj;
public:
ClassA() {
int someInt = 0;
obj = ClassB(someInt);
}
};
int main() {
return 0;
}
Check it out live
Conclusion
I would deeply recommend using the first option, the one with the initialization list because it is not needed to default construct objects before and then assigning to them. Also, this is the only option for objects that don't have an assignment operator.
UPDATE 1
One more way around this problem is using the std::shared_ptr<ClassB> obj in your ClassA as follows:
#include <iostream>
#include <memory>
class ClassB {
public:
ClassB(int i);
};
class ClassA {
std::shared_ptr<ClassB> obj;
public:
ClassA() {
int someInt = 0;
obj = std::make_shared<ClassB>(someInt);
}
};
int main() {
return 0;
}
UPDATE 2
One more possibility that came up to my mind is to calculate integer in a separate function and the just call it as part of the initialization list like in the following code:
#include <iostream>
class ClassB {
public:
ClassB(int i);
};
class ClassA {
ClassB obj;
public:
ClassA()
: obj(calculate())
{}
private:
int calculate() {
return 1;
}
};
int main() {
return 0;
}
Check it out live
You initialize members in the constructor initialization list. Like so:
ClassA() : obj(someInt) { }
I have a problem with instantiating a class as a member of another class.
Here is my code:
class myClassA{
public:
myClassA(){
printf("myClassTwo ctor");
}
void doSomething(){ printf("myClassA did something\r\n");}
};
class myClassB{
public:
myClassB(int i){
printf("myClassA ctor got %d\r\n",i);
threeMyI = i;
}
private:
int threeMyI;
};
class myClassC{
public:
myClassC(){
printf("C ctor without params\r\n");
}
myClassA instanceA;
myClassB instanceB(29); //<== Not working why??
};
I have a class myClassC which I want to have two members, one of type myClassA and one myClassB. This works well for myClassA. But as soon as I try to create an instance of myClassB, which has an ctor parameter, it fails with the following compiler error:
..\src\main.cpp:34:21: error: expected identifier before numeric constant
myClassB instanceB(29); //<== Not working why??
..\src\main.cpp:34:21: error: expected ',' or '...' before numeric constant
In my main function this type of declaration works well:
int main(void){
printf("class test\r\n");
myClassC instanceC1;
myClassA instanceA1;
myClassB instanceB1(25);
return 0;
}
But I have no idea what makes the big difference when instantiating a class with ctor parameters. Hope somebody can give me an hint what I'm doing wrong.
You can only declare member variables, you cannot instantiate them.
To invoke the constructor of a member-variable you can use the memberwise initialization paradigm in your own constructors:
struct A { // same as class A but public by default
int m_a;
A(int a) : m_a(a) {}
};
struct B {
A m_a;
int m_b;
B(int a, int b) : m_a(a), m_b(b) {}
};
Or using your code:
#include <cstdio>
class myClassA{
public:
myClassA(){
printf("myClassTwo ctor");
}
void doSomething(){ printf("myClassA did something\r\n");}
};
class myClassB{
public:
myClassB(int i) : threeMyI(i) {
printf("myClassA ctor got %d\r\n",i);
}
private:
int threeMyI;
};
class myClassC{
public:
myClassC() : instanceA(), instanceB(20) {
printf("C ctor without params\r\n");
}
myClassA instanceA;
myClassB instanceB;
};
int main()
{
myClassA a;
myClassB b(10);
myClassC c;
}
Live demo
From what I have understand, it seems that you want to use a default instantiation for your private attribute instanceB. In that case, what you are proposing is not legal, default input parameters should be set as followed
myClassC() : instanceB(29) { // mind the ":" character
printf("C ctor without params\r\n");
}
This will have the effect to call the constructor of myClassB to instantiate your private attribute instanceB with relevant default parameter.
// In A.h
class A
{
public:
enum eMyEnum{ eOne, eTwo, eThree };
public:
A(eMyEnum e);
}
// In B.h
#include "A.h"
class B
{
B();
private:
A memberA;
}
// In B.cpp
#include "B.h"
B::B(void) : memberA(A::eOne)
{}
The declaration to 'memberA' gives me a compile error using the g++ compiler:
error: 'A::eOne' is not a type
How can I overcome this? Do I simply need to create a default constructor that takes no parameters?
It sounds like you are trying to initialise a member variable. You could do something like:
class B
{
public:
B() : memberA(A::eOne) {} // Initializer list in constructor
private:
A memberA;
};
A constructor expects a eMyEnum. It is not clear why you would want B's constructor to not accept an eMyEnum parameter too. Anyway, assuming that your aim is to pass the argument to A's constructor as A::eOne (as opposed to A::eMyEnum::eOne), you could try the following code, which uses typedef.
#include <iostream>
using namespace std;
class A {
public:
typedef enum { eOne, eTwo, eThree } eMyEnum;
public:
A(eMyEnum e) {
cout << "A ctor" << endl;
}
};
class B {
public:
B() : memberA(A::eOne) {
cout << "B ctor" << endl;
}
private:
A memberA;
};
int main() {
B b;
}
// output
A ctor
B ctor
However, notice that memberA's constructor is always called with the argument as A::eOne. You have not showed how this argument is used in the constructor, but I presume that in your real code it initialises a member of A. If the member must always have the same value, make it const and remove the parameter from the constructor.
class B
{
public:
B(A::eMyEnum someValue = A::eOne) : memberA(someValue) {};
private:
A memberA;
}
eOne is not the type, eMyEnum is the type. What you're essentially saying is that "You must pass the literal 2 into this method" - it doesn't make any sense. If you don't mean to pass an enum into it, you'll have to clarify what you were going for.
I'm trying to set up a copy constructor and i'm getting this error
class Class1{
public:
int get_data();
void set_data(int);
private:
int d;
};
int Class1::get_data(){
return d;
}
void Class1::set_data(int data){
d = data;
}
class Class2 : public Class1{
Class2(const Class2&);
};
Class2::Class2(const Class2 &c2) : Class1(){
set_data(c2.set_data());
}
whats a solution to this problem. i read some of the previous questions and i understand why this is happening. but making set_data() const is not an option.
whats the accepted approach for copy constructors?
thanks,
You could just write a constructor for Class1 taking an int parameter:
class Class1 {
explicit Class1 (int i) : d (i) {}
// as before
};
class Class2 : public Class1 {
Class2 (Class2 const & c2) : Class1 (c2.get_data ()) {}
};
However, the default copy constructor should be enought here (i.e. you don't need to write your own, the compiler will do it for you).
Generally speaking, you should use initialisation lists:
http://www.parashift.com/c++-faq-lite/ctors.html
in the constructors (read the whole entry in the faq)
Edit: You forgot the 'const' qualifier for your get_data function.
Don't you want:
set_data(c2.get_data());
(and make the Class1::get_data() member function const)?
But you really should be using constructor initialization lists:
Class2::Class2(const Class2 &c2)
: Class1(c2)
{
}
This code uses the compiler-generated default copy constructor for Class1. In many cases you shouldn't use the default copy constructor or copy-assign operator overload, but here it's fine because the sole data member of Class1 is an int object.
In fact, you could even rely on the compiler-generated default copy constructor for Class2.
EDIT: Here is some example code:
#include <iostream>
class Class1{
public:
Class1() : d(0) { } // Provide a no-arg constructor to initialize `d`
int get_data() const; // Class1::get_data() is `const` because it does not change the `Class1` object.
void set_data(int);
private:
int d;
};
int Class1::get_data() const{
return d;
}
void Class1::set_data(int data){
d = data;
}
class Class2 : public Class1{
public:
Class2();
};
Class2::Class2()
: Class1()
{
}
int main() {
Class2 other_c2;
other_c2.set_data(14);
Class2 c2(other_c2);
std::cout << c2.get_data() << '\n';
}
http://codepad.org/jlplTYrH
let's say I have a class
class MyClass {
public:
AnotherClass myObject;
};
My issue is that I want to initialize myObject with arguments to it's constructor, exactly if I were declaring it on the stack during a function
AnotherClass myObject(1, 2, 3);
but I want to do this for the class member in the constructor:
MyClass::MyClass() {
myObject = ...?
...
}
The problem is exactly that. If I declare a class member that has a constructor, will C++ call the default constructor? How can I still declare the variable in the class definition but initialize it in the constructor?
Thanks for any answers!
Use the ctor-initializer. Members are initialized after base classes and before the constructor body runs.
MyClass::MyClass() : myObject(1,2,3) {
...
}
You can use an initializer list.
class MyClass {
public:
MyClass() : myObject(1,2,3){ }
AnotherClass myObject;
};
Google for Constructor initialization lists
http://www.learncpp.com/cpp-tutorial/101-constructor-initialization-lists/
class A
{
public:
A(int);
};
class B
{
public:
B();
private:
A my_a_;
};
// initialize my_a by passing zero to its constructor
B::B() : my_a_(0)
{
}
always use the initializer list:
MyClass::MyClass() :
myObject( 1, 2, 3 )
{
//myObject = don't do this, bad practice!
}
see http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.6
The best method I can think of is to initialize the member in the class ctor, like so:
class MyClass
{
public:
MyClass(int param)
: m_Object(param)
{ };
private:
OtherClass m_Object;
};
You can then explicitly initialize the member with whichever ctor you want (as well as providing multiple ctors with different params for both classes).
Or provide proper constructors:
struct Foo{
Foo(const Bar& b): myBar(b){}
Bar myBar;
}
//...
Foo myFoo1( Bar(1,2,3) );
Foo myFoo2( Bar(3,2,1) );
Or if you don't want to expose bar then you can set parameters, for example
struct Square{
Square(const int height, const int width): myDimension(width,height){}
Dimension myDimension;
}
//...
Square sq(1,2);
Square sq(4,3);