I'm currently reading C++ Primer and am at the point of class friends and member function friends and I'm having trouble figuring out how to get the code that has the following pseudoform to work:
class B;
class A {
public:
A(int i): someNum(i) { }
private:
int someNum;
friend void B::someMemberFunction(Args); // Compile error: Incomplete Type
};
class B {
public:
void someMemberFunction(Args) { /* doStuff */ }
private:
vector<A> someVector { A(5) };
};
If you try to compile in this form it gives the incomplete type error on the friend line. So the solution is to move the class B definition above class A:
class A;
class B {
public:
void someMemberFunction(Args) { /* doStuff */ }
private:
vector<A> someVector { A(5) }; // Compile error: Incomplete Type
};
class A {
public:
A(int i): someNum(i) { }
private:
int someNum;
friend void B::someMemberFunction(Args);
};
However now on the vector line, it doesn't know how to create an object of type A, since A has yet to be defined. So then A needs to be defined before B. But now we've arrived back at the original problem. I think this is called circular dependency? I don't know how to fix this with forward declarations.
Any help would be appreciated. Thanks.
I think you will either have to make the whole of class B a friend (which removes a dependency in A anyway so it's probably a good thing), or use a constructor instead of the in-class initializer.
class B;
class A {
public:
A(int i): someNum(i) { }
private:
int someNum;
friend class B;
};
class B {
public:
void someMemberFunction() { /* doStuff */ }
private:
vector<A> someVector { A(5) };
};
Or this
class A;
class B {
public:
B();
void someMemberFunction() { /* doStuff */ }
private:
vector<A> someVector;
};
class A {
public:
A(int i): someNum(i) { }
private:
int someNum;
friend void B::someMemberFunction();
};
B::B(): someVector{A(5)} { }
Related
How do I change the int 'a' inside class A but restrict the function that changes the int to ONLY class B? I do not even want A to be able to change it.
I have tried to create a friend function, but I get an error I included in the comments of the code. I then tried to just forward declare the function as a friend function in private and then actually creating the function in public, but the C class can access the public function. This despite me writing (in the private section) that the function is a friend function. Can I 'friend' a private value? I am unsure what to do here.
#include <stdio.h>
#include <iostream>
int main() {
// forward declaration
class B;
class C;
class A {
private:
int a; // private member I want to edit, but only via class B.
int a2; // I would like to NOT be able to access this in class B. I only want to access and modify int a from class B, no other variable. If possible.
// invalid use of non-static data member 'a'
friend void test(int new_value) {
a = 5;
}
friend B;
public:
};
class B {
private:
int b;
public:
change_a_value(A a_class, int new_int) {
a_class.test(new_int); // I want this to be possible.
}
};
class C {
private:
int c;
public:
change_a_value(A a_class, int new_int) {
a_class.test(new_int); // I want this to be impossible
}
};
return 0;
}
Add "void" before prototypes of change_a_value, and change the
friend B
to
friend class B
and suppress friend in
friend void test(int new_value) {
complete corrected program :
int main() {
// forward declaration
class B;
class C;
class A {
private:
int a; // private member I want to edit, but only via class B.
int a2; // I would like to NOT be able to access this in class B. I only want to access and modify int a from class B, no other variable. If possible.
void test(int new_value) {
a = new_value;
}
friend class B;
public:
};
class B {
private:
int b;
public:
void change_a_value(A a_class, int new_int) {
a_class.test(new_int); // I want this to be possible.
}
};
class C {
private:
int c;
public:
void change_a_value(A a_class, int new_int) {
a_class.test(new_int); // I want this to be impossible
}
};
return 0;
}
Compilation results are what was expected :
TestCpp2.cpp:9:14: error: ‘void main()::A::test(int)’ is private
void test(int new_value) {
^
TestCpp2.cpp:28:31: error: within this context
a_class.test(new_int); // I want this to be impossible
^
Makefile:510: recipe for target 'TestCpp2.o' failed
make: *** [TestCpp2.o] Error 1
A.hpp
class A
{
public:
class B
{
int x;
public:
B(int f);
};
void alpha(B *random);
};
A.cpp
void A::alpha(A::B *random)
{
// access x here, how to do it?
}
The private variable is getting set at some place and I want to access that value in this alpha function. How can I access x inside alpha()?
EDIT: 2nd Question:
A.hpp
class A
{
public:
class B
{
int x;
public:
B(int f);
};
virtual void alpha(B *random) = 0;
};
C.hpp
class C : public A
{
public:
virtual void alpha(B *random);
};
C.cpp
void C::alpha(A:B *random)
{
// access x here, how to do it?
}
You can make class A a "friend" of class B which allows A to access private members of B
combining your files for ease of compilation:
class A
{
public:
class B
{
friend class A; // *** HERE ***
int x;
public:
B(int f);
};
void alpha(B *random);
};
void A::alpha(B *random)
{
int x = random->x;
}
int main() {}
A class can access another class's private members if it's a friend of that other class, like in this example:
class A {
public:
class B {
friend class A;
int x;
public:
B(int f);
};
void alpha(B *random) { random->x = 10; }
};
Assuming I have these classes (question marks mark the question what I need to pass here):
class A
{
...
public:
void pass()
{
B ins;
ins.doSth(?????);
}
};
class B
{
...
public:
void doSth(const A &sth)
{
...
}
}
int main()
{
A te;
te.pass();
}
Can you pass an instance of your own class or is this just an example of a failed class structure on my side?
The current object in a member function is *this. You can pass that to another function.
You will have to consider how the classes depend on each other, and that one class cannot use the other class until the declaration is complete.
This would work though:
class A
{
//...
public:
void pass();
};
class B
{
//...
public:
void doSth(const A &sth)
{
//...
}
};
// Here both classes are completely declared
void A::pass()
{
B ins;
ins.doSth(*this);
}
int main()
{
A te;
te.pass();
}
Your class "contains" an instance of each other so you'll face an error of undeclared types. To solve this issue you need to use forward declaration.
And you'll face another problem:
If your methods doSth() and pass() are defined inlinlely then you'll face a problem: "using incomplete types". The workaround this is to implement these methods outside the class so that each object has been fully constructed before used.
The program may look like:
class A;
class B;
class A{
public:
void pass();
};
class B{
public:
void doSth(const A &sth){
}
};
void A::pass(){
B ins;
ins.doSth(*this);
}
int main(){
A te;
te.pass();
return 0;
}
I want a class that can only be instantiated as a member of another class.
Id est:
class A
{
public:
A() :
member_()
{};
void letBSayHi() { member_.sayHi(); }
private:
B member_;
};
class B
{
public:
void sayHi() { printf("hola!"); }
};
thus:
A alpha; // valid
alpha.letBSayHi(); // # hola!
B beta; // invalid
beta.sayHi(); // impossible
The singleton pattern obviously wouldn't work, as I want one instance of class B for every instance of class A. But any instantiation of class B other than as a class A-member should be prohibited.
Make B a private nested class of A:
class A {
public:
void letBSayHi() { member_.sayHi(); }
private:
class B {
public:
void sayHi() { std::cout << "hola!"; }
};
B member_;
};
Addendum re: comment: The implementation can be separated from the declaration like this:
Header:
class A {
public:
void letBSayHi();
private:
class B {
public:
void sayHi();
};
B member_;
};
Source file:
void A::letBSayHi() { member_.sayHi(); }
void A::B::sayHi() { std::cout << "hola!\n"; }
// ^^^^-- interesting part here
Well, if you want to include, why not?
class A {
#include "B.hpp"
...
};
I obtain a error: 'func' does not name a type when a member function func of a class B attempts to return a class C:
class A {
public:
class B {
public:
C func() const {
...
}
private:
friend class A;
}
class C {
public:
...
private:
friend class A;
}
private:
...
}
Whereas, if func is a member function of A, then the following does not produce this error:
class A {
public:
class B {
public:
...
private:
friend class A;
}
C func() const {
...
}
class C {
public:
...
private:
friend class A;
}
private:
...
}
How can I fix it to make the first version work?
I found a great example here.
Define class C "above" class B, or forward declare it.