Passing to a function argument a reference member variable - c++

Is it possible to pass to a function that has a reference argument a variable member of a class?
Let's say
class Foo
{
int A;
int B;
}
void foo(int& a)
{
a++;
}
void main()
{
Foo f;
foo(f.A);
}
Is this possible?

Yes, this is possible, and it works exactly how you expected it to.
But note that in your existing code, A and B are private (by default). That means nothing outside the class can access them, for any reason (which includes using them as references).
Declare them as them public:
class Foo
{
public:
int A;
int B;
};
or change Foo to a struct:
struct Foo
{
int A;
int B;
};

Related

Why is it allowed to have a class that has an incomplete type static member of itself?

I am having a hard time understanding why a class can have an incomplete type static member of itself.
For example in my code below. Why is it allowed to have an incomplete type static member of itself inside class A, but the global static variable of class type B gets an error when it is an incomplete type?
class B {
public:
B(int a) {
}
};
static B test2; //error
class A {
public:
static A test; //accepted
A(int d) {
}
};
Can someone explain to me perhaps what is going behind the scenes that gives the global static variable an error and why the static variable inside class A is accepted?
Conflating a couple of dissimilar issues here
static B test2; //error
fails because B's constructor requires arguments that haven't been provided and is private so it can't be accessed outside the class. Correct those and B is good to go.
class B {
public: // added for outside access to constructor
B(int a) {
printf("%d\n", a);
}
};
static B test2{1}; // added arguments
As for A, a static member is not part of a class instance, so the compiler doesn't need it to be complete. It doesn't take up any space, and at this point it's not being used for anything. It's just a declaration. You can declare all sorts of stuff without the compiler getting upset (so long as the declaration's syntax is good). You run into trouble when you try to use something without a definition.
Example:
void testfunc(const A &)
{
}
int main(){
testfunc(A::test);
}
fails at the linker because A::test was never defined. If you try to correct that with
class A {
public:
static A test{1}; // let's try to define it inline!
int a;
int b;
int c;
A(int d, int e) : a(d), b(e), c(15) {
}
A(int d) :A(d, 10) {
printf("%d %d %d", a, b, c);
}
};
now the compiler cares enough to report that the class is incomplete. We'll have to move the definition outside the class where it is complete
class A {
public:
static A test; //declared
int a;
int b;
int c;
A(int d, int e) : a(d), b(e), c(15) {
}
A(int d) :A(d, 10) {
printf("%d %d %d", a, b, c);
}
};
A A::test{1}; // defined
Now
void testfunc(const A &)
{
}
int main(){
testfunc(A::test);
}
will compile and link.
Documentation on the care and feeding of static members.

Set a value of a class from another class

I'm trying to set the value of a member of a class from another class using this snippet. Here is a sample of the code I'm trying to make work
class A
{
private:
int a;
public:
A()
{
a = 0;
}
A(int val)
{
a = val;
}
int GetA()
{
return a;
}
void SetA()
{
a = 290;
}
};
class B
{
B(){};
void SetB()
{
A a;
a.SetA();
}
};
int main(){
A a;
B b;
b.SetB();
cout << b.GetA();
}
How can I make this code pint out 290.I currently prints out 0
In SetB your A variable is a temporary that is destroyed when the function returns.
The way it is written in your snippet, your code won't compile, because B has no method GetA(). From your use case (the code in main()), I suspect you either want B to inherit from A:
class B : public A
{
public:
B() {];
void SetB()
{
SetA();
}
};
although that doesn't make too much sense, because in this case you could just call b.SetA() directly. Or, you want an object of type A as a member of B:
class B
{
public:
void SetB()
{
a.SetA();
}
int GetA()
{
return a.GetA();
}
private:
A a;
};
But it's a bit hard to tell from your snippet what you're actually trying to achieve.
Also, you probably want your Get…() methods to be const.
If you;re trying to achieve what I think you're trying to achieve then you're nearly there, it is just that you are creating two versions of A, one on the main stack, and one that is a temporary inside B::SetA()
try passing A as a reference parameter to B, so that there is only one version of A.
void SetB(A& a)
{
a.SetA();
}
then your calling code would be:
A a;
B b;
b.SetB(a);
cout << a.GetA();
Alternatively, pass a in the constructor of B and store A as a reference member in B;

C++ Object Initialization outside main

I have some C++ code that produces an error:
class foo{
public:
int a;
int b;
};
foo test;
test.a=1; //error here
test.b=2;
int main()
{
//some code operating on object test
}
I get this error:
error: expected constructor, destructor, or type conversion before '.' token
What does the error mean and how do I fix it?
It's called a constructor. Include one that takes the wanted values as arguments.
Like
class foo
{
public:
foo(int aa, int bb)
: a(aa), b(bb) // Initializer list, set the member variables
{}
private:
int a, b;
};
foo test(1, 2);
As noted by chris, you can also use aggregate initialization if the fields are public, like in your example:
foo test = { 1, 2 };
This also works in C++11 compatible compilers with the constructor as in my example.
This should be:
class foo
{
public:
int a;
int b;
};
foo test;
int main()
{
test.a=1;
test.b=2;
}
You can not write code outside of a method/function, you can only declare variables/classes/types, etc.
You need a default constructor:
//add this
foo(): a(0), b(0) { };
//maybe a deconstructor, depending on your compiler
~foo() { };
You cannot call the variable initialization outside a function. As mentioned in a comment
test.a=1
test.b=2
is thus invalid. If you really need an initialization, use a constructor like
class foo
{
public:
foo(const int a, const int b);
int a;
int b;
}
Otherwise you could put the initialization e.g. into the main function.

How can I accept multiple classes for one function argument?

Say I have two classes, ClassA and ClassB.
ClassB inherits ClassA, and has some additional functions and variables.
Is it possible for me to make a function that can accept either ClassA or ClassB as the same argument, and let me determine which one was used?
Yes, you can take the parameter by reference:
void foo(ClassA& x) //or const ClassA
You'll be able to pass both instances of ClassA or ClassB, and use RTTI to determine which type it actually is inside the function.
Alternatively, you can pass a pointer to ClassA, but references are to be preferred where possible.
Declare the function parameter to be a pointer or a reference to an ClassA instance (don't pass it by value or the input instance will get sliced at runtime). Then you can use dynamic_cast if you need to access ClassB-specific functionality. For example:
class ClassA
{
public:
int a;
virtual ~ClassA() {}
void DoSomething();
};
class ClassB : public ClassA
{
public:
int b;
void DoSomethingElse();
};
void func(ClassA *obj)
{
int a = obj->a;
obj->DoSomething();
ClassB *objB = dynamic_cast<ClassB*>(obj);
if (objB)
{
int b = objB->b;
objB->DoSomethingElse();
}
}
int main()
{
ClassA a;
func(&a);
ClassB b;
func(&b);
return 0;
}
Here's an idea with a bit of indirection. The function Consumer::accept accepts both objects of type A and type B, and the specific behaviour is implemented by those classes rather than by your consumer.
struct Consumer;
struct A
{
virtual ~A() { }
virtual int use(Consumer &);
};
struct B : A
{
virtual int use(Consumer &);
};
struct Consumer
{
void accept(A & x)
{
int n = x.use(*this);
do_more_stuff(n);
}
void do_more_stuff(int);
// ...
};

How can I declare a friend function in a namespace that takes an inner class as a parameter?

Consider this code:
namespace foo {}
class A
{
class B
{
};
friend int foo::bar( B& );
};
namespace foo
{
int bar( A::B& )
{
}
}
G++ 4.4.3 tells me:
friendfun-innerclass.cpp:21: error: 'int foo::bar(A::B&)' should have
been declared inside 'foo'
But I can't declare:
namespace foo
{
int bar( A::B& );
}
before the class A definition because A::B hasn't been declared. And I can't declare "class A::B" obviously, to declare class B I have to give the definition of class A, and as far as I know the "friend" declarations have to be inside the definition of class A.
What's strange to me is that if I take function "bar()" out of namespace foo everything works fine. It seems counterintuitive to me that having a function inside a namespace or not inside a namespace changes whether the compiler will accept a friend function declaration in the class.
Does anybody know of a way to proprerly structure all the declarations and such to get this to work?
Can't be done the way you want to, because you would have to forward declare a nested class (which you can't) in order to provide a prototype for foo::bar.
As a first attempt to get around this problem, I would probably resort to making foo::bar a function template. That way the compiler will resolve the types after A and B are known.
Test harness:
namespace foo
{
template<class B> int bar(B&);
};
class A
{
class B
{
template<class B> friend int foo::bar( B& );
int n_;
public:
B() : n_(42) {}
};
public:
B b_;
};
template<class B> int foo::bar(B& b)
{
return b.n_;
}
int main()
{
A a;
foo::bar(a.b_);
}
I believe that you need ::foo::bar.
You can't because you can't forward-declare inner classes.
This is a close as you're gonna get.
namespace foo {
class A_B;
int bar(A_B &);
}
struct A
{
class B
{
};
friend int foo :: bar (A_B&);
};
namespace foo
{
struct A_B : public A :: B {
// constructors, delegated if you're C++11 :-)
};
int bar (A_B &)
{
}
}
You lose privatehood of A::B, but if you think about it, that makes sense, or you wouldn't be able to implement foo::bar.
It doesn't look like you can do that. What you can do is forward declare a class with a static member, and the class gets friendship. But any time you use friendship at least take one more look at your design and ask yourself why. It may be fine or there may be a better answer.
namespace foo { class bar; }
class A
{
class B
{
};
friend class ::foo::bar;
};
namespace foo
{
class bar
{
public:
static int run_bar( A::B& )
{
}
};
}
You can't do it because there is no way to write a forward declaration of A::B and hence forward declare foo(A::B&).
However, you can use a trick known as "friend name injection" to declare (and possibly define) a friend function in the class definition. This way you can call that friend function without namespace qualifiers (e.g. bar(b) instead of foo::bar(b)) and argument-dependent lookup will successfully resolve the call:
struct A
{
struct B {};
friend int bar(B&) { // inject bar() into the outer namespace
// implementation here
}
};
namespace foo
{
int foo()
{
A::B b;
return bar(b); // it calls bar(B&) declared in A
}
}