Troubles with reference variables/pointers an class members [C++] - c++

I've been working on a project and have quite a few classes, a few of which look like this:
class A
{
// stuff;
};
class B
{
A& test;
public:
B(A& _test) :
test(_test)
{};
void doStuff();
};
class C
{
A foo;
B bar(foo);
void exp()
{
bar.doStuff();
}
};
This ends up breaking in class C when C::foo is not a type name. In my bigger project, where everything is broken up into their separate .cpp and .h files, I don't see that error if I #include"C.h" in B.h, but there is still an error in C.cpp where bar is completely unrecognized by my compiler (Visual Studio 2013). There error persists even if A& is an A* instead (changing the code from references to pointers where necessary, of course). Does anyone have any tips to what is going on here?

This line of code:
B bar(foo);
Attempts to declare a member function named bar which returns a B and takes an argument of type foo. However, in your code, foo is not a type - it's a variable. I'm guessing you meant to initialize bar instead:
B bar{foo}; // non-static data member initializers must be done with {}S
or just write out the constructor:
C()
: bar(foo)
{ }
Additionally, this constructor assigns your reference test to the temporary _test:
B(A _test) :
test(_test)
{ }
You want to take _test by reference:
B(A& _test) : test(_test) { }

Related

Defer calling constructor of member object declared in header until source file

I'd like to do declare a member object within the class declaration within my header file. I want to defer the calling of the member's constructor until the corresponding source file.
This is ideally what I'd like, just for illustration:
// foo.h
class Bar(string First, string Second);
class Foo : public Base {
public:
Foo(int a);
Bar b; // I don't want to construct here!
...
// foo.cc
Foo::Foo(int a)
: base(a)
, b("first", "second") // <-- construct here
{}
edit: The code above is calling the "default constructor" for Bar. I get:
error: could not convert ‘{arg}’ from ‘<brace-enclosed initializer list>’ to ‘Bar’
Bar bar;
Changing the type of b to a pointer will ripple through too many things.
Changing it to a REFERENCE is probably tenable. In the code below, since no constructor is called in the header file, that's okay for my needs!
// foo.h
class Bar;
class Foo : public Base {
public:
Foo(int a);
Bar& b; // now it's a non-constant reference, but unassigned
...
// foo.cc
Foo::Foo(int a)
: base(a)
, b{"first", "second"} // <-- construct here
{}
However, this results in the error: non-const lvalue reference to type 'Bar' cannot bind to an initializer list temporary. That makes sense too.
I guess I'm asking how would you do this? Is something like std::reference_wrapper going to be useful?
C++11 is a restriction.
The constructor of a member object is called from all constructors of the containing class. That includes compiler-generated constructors.
Hence, you need to make sure that the definitions of all these constructors are in foo.cc. Now you only show Foo::Foo(int), but that's not the constructor which is causing the problem.
I can and do include the full definition
It's exceedingly difficult to get a straight response to you so I'll go with that quote specifically and assume you meant you have a fully defined Bar type before your Foo definition.
If that's the case, your first part of the code does work as intended (once you fix the weird syntax and semantic and every other kind of errors, of course). Specifically, this works as expected:
#include <string>
using namespace std;
struct X {
X(string a, string b) {}
};
struct Y {
X x;
Y() : x("a", "b") {}
};

Using Child on a function with Parent's Typing

I was looking to create a function that is capable of working with any Derived Object of A.
However in this example, I can't seem to be able to use B Object in a function that has a A Typing on it. Is there any way I pass B into the Function?
class A {
public:
A() {
}
};
class B :A {
public:
B() {
}
};
void function(A a) {
return;
}
int main(void) {
B b();
function(b);
}
I've commented on the fixes needed inline:
class A {
public:
A() {}
};
class B : public A { // public inheritance or A will be an inaccessible base of B
public:
B() {}
};
void function(const A& a) { // take a reference to an A to avoid copy-slicing
// ... work with the A part of the object you reference with `a`
}
int main() { // void not needed (but not an error as such)
B b; // not a function declaration anymore
function(b);
}
Actually you are lucky. You made two mistakes that caused passing b to the function fail, while in fact without that other mistakes you can pass b to the function but it would do the wrong thing silently.
First the two mistakes: B b(); declares a function. To declare a default constructed B you write B b;. Then B inherits privately, hence you cannot convert a B to an A. Thats what the error your code causes have told you.
However, after fixing those (and removing user declared constructors taht shouldnt be there when they do nothing)...
class A {};
class B : public A {};
void function(A a) {}
int main(void) {
B b;
function(b); // object slicing !!
}
This code compiles without errors, but usually it does the wrong thing!
Any B can be converted to an A because the inheritance is public, but what happens is object slicing: What is object slicing?. If B had any members not in A then they would all be lost when passing it to function. Its not an issue here because neither A nor B have any members, but in general you want to avoid objects to get sliced.
TL;DR: References / pointers are needed for polymorphism. Pass by (const) reference:
void function(const A& a) {} // does not modify a
void function(A& a) {} // modifies a

Constructor problems with class inside another class

I think the question title may be impossible to get right but, I have a class (lets call it A) which has a constructor that needs a pointer to another class (called B). This would be fine but when I define a class in a third class (called C), then I get this error after putting a variable into the constructor: error: expected identifier before ‘&’ token, then if I remove the & I get: error: ‘ClassA’ is not a type.
For those who can't understand what I just said (I don't blame you), here is an example:
class A
{
private:
int number;
//etc, etc...
};
class B
{
private:
A* ClassAPntr;
public:
B(A* objectPointer)
{
ClassAPntr = objectPointer;
}
};
class C
{
private:
A ClassA;
B ClassB(&ClassA);
};
int main()
{
C classC;
}
You didn't actually declare a constructor for class C. What you meant to do was this:
class C
{
public:
C()
: b(&a) // you have to provide the arguments to B's constructor here
{ }
private:
A a;
B b; // ... not here
};
Just for clarification, when you did composition by adding A classA private object to class C, the compiler accept this step because A has undefined constructor which means the compiler will make a default constructor for you and call it when make A classA.
The problem in class B because it has a non-default user defined constructor which means that compiler should force you to call it in class C through constructor initialization list or through curly braces in c++11, so it becomes your responsibility simply because compiler can't know which address for which class A Object you are going to pass for class B
constructor.
So why did you get this error message : class A is not a type or expected identifier before ‘&’ token?
the answer is that compiler considered B ClassB(&ClassA) a declaration for a private function with name ClassB and a return value of type B class.
and because you never use this function in your class the compiler will never give you any error related to definition. and you will also never use this member function in other functions like main because it is private
to produce the undefined reference error you can modify c class to be like this:
class C
{
private:
A classA;
B classB();
friend B func() ;
};
B func() {
C c;
return c.classB(); // undefined reference Error
}

Why am I getting undefined type error after a forward-declaration?

I'm using this code in C++ CLI. However this shouldn't make any difference from C++.
I'm looking for a solution to get rid of that error.
Code :
ref class B;
ref class A;
public ref class A
{
public:
A() {}
B^ b;
void HelloFromA(){
b->HelloFromB();
}
};
public ref class B
{
public :
A^ a;
B() {}
void HelloFromB(){
a->HelloFromA();
}
};
You need to move the bodies of the functions that invoke member functions on the forward-declared classes outside of the headers, to places where definitions are available:
void A::HelloFromA(){
b->HelloFromB();
}
Otherwise, the compiler knows that B is available, but it does not know that B has the HelloFromB member function that takes no arguments.

C++ : const references and initialization order

I am wondering if I am using the good approach in the following :
I want to construct a parent class (class A), this class should own an instance of a given "Foo" class
I want the parent class to own a child class member (class B) and this member should have a reference to the foo member of the parent class.
The code below seems to works, however I am wondering whether I was just "lucky" that the compiler was sympathetic enough.
For clarity, I added comment and my question in the comments below.
Thanks !
struct Foo
{
std::string mValue;
};
class B
{
public:
B(const Foo & foo) : mFoo_External(foo) {}
private:
const Foo & mFoo_External; //this is an external reference to the member
//(coming from A)
};
class A
{
public:
//Here is the big question
//Shall I use :
// A(const Foo & foo) : mFoo(foo), mB(mFoo) {}
// or the declaration below
A(const Foo & foo) : mFoo(foo), mB(foo) {}
private:
//According to my understanding, the declaration
//order here *will* be important
//(and I feel this is ugly)
const Foo mFoo;
B mB;
};
void MyTest()
{
std::auto_ptr<Foo> foo(new Foo());
foo->mValue = "Hello";
A a( *foo);
foo.release();
//At this point (after foo.release()), "a" is still OK
//(i.e A.mB.mFooExternal is not broken, although foo is now invalid)
//
//This is under Visual Studio 2005 :
//was I lucky ? Or is it correct C++ ?
}
No, this is broken. Your mB will hold a reference to whatever you passed to the constructor of the A object, not to mFoo. Instead, you should say:
A(const Foo & foo) : mFoo(foo), mB(mFoo) { }
Note that mB is a copy of the constructor argument, and not a reference, so your MyTest function is fine.
Since you want your B object to hold a reference to the parent's member, you must initialize mB with mFoo not foo.
You are correct that the order of the member variables is important, since it determines the order of the initialization. It might come as a surprise that the order of the initializers in the constructor does not determine the order they are called! See Constructor initialization-list evaluation order.