// 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.
Related
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.
I have a simple question. How would you go about passing an instance of a class to a constructor of another class in c++? I have experience in C, however I am struggling with the syntax of c++.
For example say I have Class A and want to pass and Instance of it to Class B.
A.h
class A {
A();
virtual ~A();
public:
B *newb;
}
A.cpp
A::A() {
newb = new B(this);
}
b.h
class B {
B(A *instanceA);
virtual ~B();
}
Could someone please provide me with a simple example? It would be much appreciated.
EDIT: I tried this concept with my current code, but kept getting errors. Sorry I wanted to make sure that I used the right principle. This is a snippet of the code that I am currently working on.
//SentencSelection.h
class SentenceSelection
{
public:
SentenceSelection(TestBenchGui *test);
virtual ~SentenceSelection();
//do stuff
};
//SentencSelection.cpp
#include <iostream>
#include "SentenceSelection.h"
using namespace std;
SentenceSelection::SentenceSelection(TestBenchGui *test)
{
//do stuff
}
SentenceSelection::~SentenceSelection()
{
}
//TestBenchGui.h
#include "SentenceSelection.h"
class TestBenchGui
{
public:
TestBenchGui();
virtual ~TestBenchGui();
private:
SentenceSelection *selection;
};
//TestBenchGui.cpp
#include "TestBenchGui.h"
#include "SentenceSelection.h"
using namespace std;
TestBenchGui::TestBenchGui()
{
selection = new SentenceSelection(this);
}
TestBenchGui::~TestBenchGui()
{
}
When I compile this in eclipse I get the follwing error "expected constructor, destructor, or type conversion before ‘(’ token" for the line - "SentenceSelection::SentenceSelection(TestBenchGui test)" in SentenceSelection.h.
I believe the code you have does pretty much what you are asking, but there are a couple of syntax errors that are probably holding you back from compilation (and thus leading to some confusion). Below is code that I put in a single file (main.cpp) and was able to compile. I added some comments and print statements to highlight the difference between DECLARATIONS and IMPLEMENTATIONS:
#include <iostream>
using std::cout;
using std::endl;
// forward declaration so we can refer to it in A
class B;
// define A's interface
class A {
public:
// member variables
B *newb;
// constructor declaration
A();
// destructor declaration
virtual ~A();
}; // note the semicolon that ends the definition of A as a class
class B {
public:
// B constructor implementation
B(A *instanceA){cout << "I am creating a B with a pointer to an A at " << instanceA << endl;}
// B destructor implementation
virtual ~B(){cout << "Destructor of B" << endl;}
}; // note the semicolon that ends the definition of B as a class
// A constructor implementation
A::A(){
cout << "I am creating an A at " << this << ", allocating a B on the heap..." << endl;
newb = new B(this);
}
// A destructor implementation
A::~A(){
cout << "Destructor of A, deleting my B...." << endl;
delete newb;
}
int main(){
A an_a;
}
Output for my system from running the above program:
I am creating an A at 0x7fff64884ba0, allocating a B on the heap...
I am creating a B with a pointer to an A at 0x7fff64884ba0
Destructor of A, deleting my B....
Destructor of B
Hope this helps.
For example say I have Class A and want to pass and Instance of it to Class B.
If you intend to pass a pointer to the instance, then you have already figured it out. The constructor that you declared takes an A* as an argument:
B(A *instanceA);
#include <iostream>
using namespace std;
class B
{
public:
B(){};
int x;
~B(){};
};
class A
{
public:
A(){}; // default constructor
A(B& b) // constructor taking B
{
y = b.x;
}
~A(){};
int y;
};
int main()
{
B myB;
myB.x = 69;
A myA(myB);
cout << myA.y << endl;
return 0;
}
I answer strictly your question:
If you want to pass a instance on a constructor best practice is pass as a reference:
class CA{
CB &b;
public:
CA( CB &p_b) : b(p_b){};
virtual ~CA();
};
But in your example you have a classes with cross references that is another case
The following working code displays the smaller of two given numbers.
#include "stdafx.h"
#include <iostream>
using namespace std;
template <class T>
class Bucky {
public:
Bucky(T a, T b) {
first = a;
second = b;
}
T smaller() {
return (first<second?first:second);
}
private:
T first, second;
};
int main() {
Bucky <int>obj(69, 105);
cout << obj.smaller() << endl;
return 0;
}
I would like to derive from class 'Bucky' and create a subclass having a member function that displays "Hi There!"
Please help.
P.S. Here is my best failed attempt to create my subclass:
template <class T>
class mySubclass : public Bucky<T>
{
public:
mySubclass(T a, T b) { // error C2512: 'Bucky<T>' : no appropriate default constructor available
//first = a;
//second = b;
}
void greet() {
cout << "Hi there!";
}
};
When you construct a derived class, it will also construct its base class. If you don't explicitly specify this, it will attempt to construct the base class using its default constructor (with no arguments). However, your base class doesn't have a default constructor. Instead, you want to delegate to the constructor of Bucky that takes two T arguments:
mySubclass(T a, T b)
: Bucky<T>(a, b) { }
As you can see, this uses a strange syntax beginning with : and leaves the constructor body empty. This syntax is the member initialization list. It says that we're initialising the Bucky<T> base class by passing a and b to its constructor. In fact, you should also use this for your Bucky constructor:
Bucky(T a, T b)
: first(a), second(b) { }
Here we are initialising the first and second members with a and b respectively.
The mySubclass constructor does not explicitly initialize the base class object Bucky. So the compiler will attempt to do so implicitly by calling the default constructor for Bucky. As the error says, Bucky does not have a default constructor. To fix the error, initialize Bucky explicitly in the contructor's member initializer list.
mySubclass(T a, T b)
: Bucky<T>(a, b)
{}
You should also use the member initializer list to initialize Bucky's data members
Bucky(T a, T b)
: first(a)
, second(b)
{}
As the compiler points out, it cannot find an appropriate default constructor for your base class. So, you need to call one explicitely in the member initializer list.
template <class T>
class mySubclass : public Bucky<T>
{
public:
mySubclass(T a, T b) : Bucky<T>(a, b) { }
void greet() {
cout << "Hi there!";
}
};
You can call the base constructor from the derived constructor as such:
mySubClass(T a, T b)
: Bucky(a, b)
{
}
As the error states, by implementing a constructor (one that accepts arguments) you have removed the default constructor. And when you create a constructor for a subclass it must initialize its base class. The way to do this is to call the base constructor in the initializer list, as someone in the comments mentioned.
template <class T>
class a:public Bucky<T> {
public:
a(T r, T l): Bucky<T>(r, l) {}
void Hello(void) { std::cout << "Hello there!" << std::endl; }
};
int main() {
Bucky <int>obj(69, 105);
a<int> obj2(69, 105);
obj2.Hello();
cout << obj.smaller() << endl;
return 0;
}
I think this get's you what you're looking for.
When a constructor in a superclass receives arguments, it is no longer a default constructor, right? For example
class a {
public:
int a;
int b;
a(int c, int d){
cout<<"hello";
};
}
Now when I try to make a subclass, the program causes an error, it says "no default constructor is defined in the super class". How can I solve this problem? I know that if I remove the arguments, everything is going to be fine but I'm told not to do so in my C++ test. Please help me figure it out.
If your base class isn't default-constructible, or if you don't want to use the base class's default constructor, then you simply have to tell the derived class how to construct the base subobject:
struct b : a
{
b(int n) : a(n, 2*n) { }
// ^^^^^^^^^ <-- base class initializer, calls desired constructor
};
You normally deal with this with an initializer list:
#include <iostream>
class a {
public:
a(int c, int d) { std::cout << c << " " << d << "\n"; }
};
class b : public a {
public:
b() : a(1, 2) {}
};
int main() {
b x;
return 0;
}
You have to provide a constructor which takes no argument yourself.
a::a()
{
}
Once you provide any constructor for your class the compiler does not generate the implicit default constructor which takes no arguments. So if your code then needs a no arguments constructor you will have to provide it yourself.
Can I call constructor of a member in my Class's constructor?
let say If I have a member bar of class type foo in my class MClass. Can I call constructor of bar in MClass's constructor? If not, then how can I initialize my member bar?
It is a problem of initializing members in composition(aggregation).
Yes, certainly you can! That's what the constructor initializer list is for. This is an essential feature that you require to initialize members that don't have default constructors, as well as constants and references:
class Foo
{
Bar x; // requires Bar::Bar(char) constructor
const int n;
double & q;
public:
Foo(double & a, char b) : x(b), n(42), q(a) { }
// ^^^^^^^^^^^^^^^^^^^
};
You further need the initializer list to specify a non-default constructor for base classes in derived class constructors.
Yes, you can:
#include <iostream>
using std::cout;
using std::endl;
class A{
public:
A(){
cout << "parameterless" << endl;
}
A(const char *str){
cout << "Parameter is " << str <<endl;
}
};
class B{
A _argless;
A _withArg;
public:
// note that you need not call argument-less constructor explicitly.
B(): _withArg("42"){
}
};
int main(){
B b;
return 0;
}
The output is:
parameterless
Parameter is 42
View this on ideone.com
Like this:
class C {
int m;
public:
C(int i):
m(i + 1) {}
};
If your member constructor wants parameters, you can pass them. They can be expressions made from the class constructor parameters and already-initialized types.
Remember: members are initialized in the order they are declared in the class, not the order they appear in the initialization list.
Through initializer list, if base class doesn't have a default constructor.
struct foo{
foo( int num )
{}
};
struct bar : foo {
bar( int x ) : foo(x)
// ^^^^^^ initializer list
{}
};
Yes, you can. This is done in the initialization list of your class. For example:
class MClass
{
foo bar;
public:
MClass(): bar(bar_constructor_arguments) {};
}
This will construct bar with the arguments passed in. Normally, the arguments will be other members of your class or arguments that were passed to your constructor. This syntax is required for any members that do not have no-argument constructors.