I have a class that needs to keep a list of references of all its objects.
For example:
//A.cpp
class A {
A() {}
someMethod() {}
someOtherMethod() { mapA[0]->someMethod(); }
}
//main.cpp
#include <map>
std::map<int, A*> mapA;
int main(int argc, char const *argv[]) {
int count = 0;
A* a = new A();
mapA[count] = a;
count++;
}
However, because mapA is only global to main.cpp, A.cpp can't reference it. I tried using extern, but because the map uses the same class A, I don't know where to put it.
What's the best way to go about this?
You might register them in constructor, and make the static var in the class:
// a.hpp
class A {
public:
A() { as.insert(this); }
A(const A& rhs) { as.insert(this); }
~A() { as.erase(this); }
static std::set<A*> as; // Declaration
};
// a.cpp
std::set<A*> A::as; // Definition
Related
How do I initialize pointer class B foo inside class A? I am new to C++.
Header.h
namespace Core
{
enum type
{
Left, Right
};
template<type t>
class B
{
public:
B(int i);
private:
type dir;
int b = 12;
};
class A
{
public:
B<Left> *foo;
};
}
Source.cpp
namespace Core
{
template<type t>
B<t>::B(int i)
{
dir = t;
b = i;
}
}
int main()
{
Core::A *a = new Core::A;
a->foo = new Core::B<Core::Left>(10);
return 0;
}
Source.cpp needs a #include "Header.h" statement, and Header.h needs a header guard.
Also, you need to move the implemention of B's constructor into the header file. See Why can templates only be implemented in the header file?.
Try this:
Header.h:
#ifndef HeaderH
#define HeaderH
namespace Core
{
enum type
{
Left, Right
};
template<type t>
class B
{
public:
B(int i);
private:
type dir;
int b = 12;
};
class A
{
public:
B<Left> *foo;
};
template<type t>
B<t>::B(int i)
{
dir = t;
b = i;
}
}
#endif
Source.cpp
#include "Header.h"
int main()
{
Core::A *a = new Core::A;
a->foo = new Core::B<Core::Left>(10);
//...
delete a->foo;
delete a;
return 0;
}
I would suggest taking it a step further by inlining B's constructor and giving A a constructor to initialize foo:
Header.h:
#ifndef HeaderH
#define HeaderH
namespace Core
{
enum type
{
Left, Right
};
template<type t>
class B
{
public:
B(int i)
{
dir = t;
b = i;
}
private:
type dir;
int b = 12;
};
class A
{
public:
B<Left> *foo;
A(int i = 0)
: foo(new B<Left>(i))
{
}
~A()
{
delete foo;
}
};
}
#endif
Source.cpp
#include "Header.h"
int main()
{
Core::A *a = new Core::A(10);
//...
delete a;
return 0;
}
How do I initialize pointer class B foo inside class A?
Option 1
Construct a B<Left> with an assumed value.
class A
{
public:
B<Left> *foo = new B<Left>(0);
};
Option 2
Add a constructor of A that accepts an int that can be used to construct a B<Left> .
class A
{
public:
A(int i) : foo(new B<Left>(i)) {}
B<Left> *foo;
};
Word of caution
Before you down too far into using pointers to objects in your classes, consider the following:
What is The Rule of Three?
https://en.cppreference.com/w/cpp/memory, specially shared_ptr and unique_ptr.
Can I do an defined constructor which contains an object from another class?
If i can do how is defined.
this is an example.I do classes and how could be defined the constructor of class "Abonati" which contains an object "abonament"
I need that because i have another class which contain a vector of "abonati"
#pragma once
#include"abonament.h"
#include<iostream>
#include<vector>
using namespace std;
class abonati
{
char*nume_abonat;
int nr_telefon;
char *numefisier;
abonament *a;
public:
abonati();
abonati(char*, int , char *,abonament *);
abonati(abonati&a);
void Send();
~abonati();
};
`#pragma once
#include"abonati.h"
class abonament
{
protected:
int cost;
public:
abonament();
abonament(int costa);
virtual ~abonament();
};
#include "abonament.h"
abonament::abonament()
{
this->cost = 0;
}
abonament::abonament(int costa)
{
this->cost = costa;
}
abonament::~abonament()
{
}
`
I guess you would like to pass an class instance to another class constructor
Here is an example
#include <iostream>
class A
{
public:
A(int value) : m_int(value) {}
int GetInt() { return m_int; }
private:
int m_int;
};
class B
{
public:
B(A& a) : m_int(a.GetInt()) {} // Here constructor expects instance of class A
int GetInt() { return m_int; }
private:
int m_int;
};
int main()
{
A a(2);
B b(a); // Pass an object of class A to constructor of class B
std::cout << b.GetInt() << std::endl;
return 0;
}
Prints
2
I'm working on some code, which has a model similar to the following (it is a small part of a much larger application). In short, one of the classes (Class B) registers itself with another class (Class A) by passing this. Class B gets destroyed at some point in the larger application. Class A has a method invoked which depends on B and B is invoked after being destroyed (after doing a nullptr check). Rewriting this application to not have this pattern is not really an option. In A::GetVal() how do I correctly determine if B has already been destroyed? I can change the method signature for RegisterB(), but ultimately B needs to register itself with A and B can be destroyed at any time.
Classes.h:
#ifndef CLASSES_H
#define CLASSES_H
#pragma once
#include <iostream>
class B;
class A
{
private:
B* m_b;
int m_val;
public:
A(int val) : m_val(val) {}
int GetVal();
void RegisterB(B* b) { m_b = b; }
};
class B
{
private:
int m_val;
public:
B(int val) : m_val(val) {}
int GetVal() { return m_val; }
void RegisterWithA(A* a) { a->RegisterB(this); }
};
#endif
Classes.cpp:
#include "stdafx.h"
#include "Classes.h"
int A::GetVal()
{
if (m_b != nullptr)
{
m_b->GetVal(); // How do I prevent this branch from getting called?
}
else
{
return -1;
}
}
And main:
#include "stdafx.h"
#include "Classes.h"
int _tmain(int argc, _TCHAR* argv[])
{
A* a = new A(-1);
B* b = new B(1);
b->RegisterWithA(a);
delete b;
int result = a->GetVal();
delete a;
return 0;
}
You can use std::shared_ptr<> in conjunction with std::weak_ptr<> to handle this.
#include <iostream>
#include <memory>
using namespace std;
class B;
class A
{
private:
std::weak_ptr<B> m_b;
int m_val;
public:
A(int val) : m_val(val) {}
int GetVal();
void RegisterB(std::shared_ptr<B> b) { m_b = b; }
};
class B : public std::enable_shared_from_this<B>
{
private:
int m_val;
public:
B(int val) : m_val(val) {}
int GetVal() { return m_val; }
void RegisterWithA(A* a) { a->RegisterB(shared_from_this()); }
};
int A::GetVal()
{
if(auto b = m_b.lock())
{
m_val = b->GetVal();
}
return m_val;
}
int main()
{
auto a = std::make_shared<A>(-1);
auto b = std::make_shared<B>(1);
b->RegisterWithA(a.get());
b.reset();
int result = a->GetVal();
std::cout << result << '\n';
return 0;
}
You should rethink your design. Why are you using heap allocation of objects when it would be perfectly acceptable in this situation to have them on stack? Why are you not using inheritance and having B inherit from A? This whole quandry goes away when you don't force yourself to do unnecessary things.
If, for some reason you're forced to have have disparate heap-based objects then do something like wrap the allocated instance into a unique_ptr<> and pass the instance around or alternatively, as stated in Chad's answer, wrap it into a shared_ptr<> and maintain a weak_ptr<> reference for usage.
Unless the use of weak_ptr can be proven to be minimal and local to classes A and B (in that case it will be surely the recommended modification), it seems to me that a localized and minimal modification could be:
add to class A some unregisterB method (sets m_b to null)
maintain in B a set of A pointers. One sole pointer will do if the association is not many-to-one, that is, if an instance of B cannot be registered within many instances of A.
In B::~B, call unregisterB on all the A's in the set.
in B::RegisterWithA, add that instance (pointer) of A to the list.
The advantage here is that no other modifications are required in the application, only in the classes A and B.
I want to use one pointer ( _ref ) to point to different class types. In order to use it, I must cast it to the type that is addressed. I cannot do that because of the incomplete type that is at line 5. If i move the definition of B to line 5, it requires class A to be defined.
#include <iostream>
#include <vector>
#include <string>
class B;
class A{
void *_ref;
std::string _reft;
public:
void setref(A &a){
_ref=&a;
_reft=typeid(a).name();
}
void setref(B &b){
_ref=&b;
_reft=typeid(b).name();
}
void test(){
if(_ref && _reft==std::string(typeid(B).name())){
std::cout<<"Ref to B: ";
static_cast<B*>(_ref)->test(); //error here
}
}
};
class B{
std::vector<A> a;
public:
A A(int i){
return a[i];
}
void test(){
std::cout<<"IT WORKS!";
}
};
int main(){
A a;
B b;
a.setref(b);
a.test();
return 0;
}
Move the implementation of the function that requires B to be complete out of the class; put it either in a source file, or inline after the definition of B:
class A{
// ...
void test();
};
class B{
// ...
};
inline void A::test(){
// ...
}
If you use pointers rather than references you will be able to do this.
You need to change your function definitions to use pointers not references.
Then when calling the functions use the address of the object.
This is a sample code of my project.
I have to make the std::auto_ptr to a friend class, so that it can access private members.
#include "stdafx.h"
#include <map>
#include <iostream>
//sample namespace
namespace test
{
//class A
class A
{
public:
//making class B to friend , so that it can access private members
friend class B;
private:
int i;
//constructor - private
A(int in)
{
i = in;
}
// private destructor;
~A()
{
std::cout<<"\n Ending";
getchar();
}
};
//map to store A pointer
typedef std::map<int, std::auto_ptr<A>> MAP;
//class B, friend of A
class B
{
private:
MAP Map;
public:
//making auto_ptr to a friend class , so that it can call the destruct all the A pointer.
friend class std::auto_ptr; //Getting error like" error C2990: 'std::auto_ptr'
//: non-class template has already been declared as a class template
B()
{
std::auto_ptr<A> a(new A(1));
std::auto_ptr<A> b(new A(2));
std::auto_ptr<A> c(new A(3));
Map[0] = a;
Map[1] = b;
Map[2] = c;
}
~B()
{
}
};
}
int _tmain(int argc, _TCHAR* argv[])
{
using namespace test;
B ab;
return 0;
}
But when i tried to make it to a friend i am getting error... please help....
Because auto_ptr is a template class, you'll need something like:
friend std::auto_ptr<B>;