I have a Base class with several derived classes:
class Base {
private:
long id;
public:
Base() {}
~Base() {}
Base &operator = (long temp) {
id = temp;
return *this;
}
};
template <class C>
class Temp1 : public Base {
public:
Temp1() {}
~Temp1() {}
//do something;
};
template <class C>
class Temp2 : public Base {
public:
Temp2() {}
~ Temp2() {}
//do something;
};
class Executor1 : public Temp1<int> {
public:
Executor1() {}
~Executor1() {}
};
class Executor2 : public Temp2<char> {
public:
Executor2() {}
~Executor2() {}
};
I want those classes to support operator =.
e.g:
int main()
{
long id1 = 0x00001111, id2 = 0x00002222;
Executor1 exec1;
Executor2 exec2;
exec1 = id1; //exec2.id = id1;
exec2 = id2; //exec2.id = id2;
}
I define operator = in Base whose declaration is Base &operator = (long);.
But there is a problem clearly that = doesn't work to derive classes. So I have to define operator = totally do the same thing to every Executor.
How to deal with this case in Base in a better way?
You have to pull the =-operator into the scope of the class:
class Base
{
public:
long id;
Base& operator=(long id)
{
this->id = id;
return *this;
}
};
class Temp2
: public Base
{
public:
using Base::operator=;
};
You have to pull the operator= into the scope because the implicitly generated copy operator= of Temp2 was hiding the operator= of Base. Got this hint from #Angew from's comment.
Related
I have base class and derived class in C++.
I want to determine if the data of the derived class is the same using the pointers of the base class.
enum type
enum class FruitType: int{
Apple,
Orange,
};
base class
class Base{
public:
Base(FruitType t): fruit_type(t){}
FruitType fruit_type;
};
derived class
class Apple : public Base{
public:
Apple(int i): Base(FruitType::Apple), foo(i){}
int foo;
};
class Orange : public Base{
public:
Orange(float f): Base(FruitType::Orange), bar(f){}
float bar;
};
initialize
// initialize
std::vector<Base*> fruit_list_ = {
new Apple(42),
new Orange(0.f),
new Apple(1) };
Is there any way to check with HasSameData()?
Base* HasSameData(const Base* pCompare){
for (const auto& list : fruit_list_)
{
if( pCompare->fruit_type == list->fruit_type ){
// how to check same data...?
if( /* ... */ ){
return list;
}
}
}
return nullptr;
}
int main(){
// check same data
Base* pCompare = fruit_list_[2];
if(HasSameData(pCompare)){
// I want to return fruit_list_[2] pointer...
}
}
You could add an abstract method sameData() to the base case
class Base{
public:
Base(FruitType t): fruit_type(t){}
FruitType fruit_type;
virtual bool sameData(const Base& other) const = 0;
};
Override in the derived classes:
class Apple : public Base{
public:
Apple(int i): Base(FruitType::Apple), foo(i){}
int foo;
virtual bool sameData(const Base& other) const {
const Apple* apple = dynamic_cast<const Apple*>(&other);
return apple && apple->foo == foo;
}
};
class Orange : public Base{
public:
Orange(float f): Base(FruitType::Orange), bar(f){}
float bar;
virtual bool sameData(const Base& other) const {
const Orange* orange = dynamic_cast<const Orange*>(&other);
return orange && orange->bar == bar;
}
};
And use it as follows:
// how to check same data...?
if( pCompare->sameData(*list) ){
The simplest way is to use a virtual function to compare equality and implement the comparison logic in the body of the virtual function.
class Base{
public:
Base(FruitType t): fruit_type(t){}
FruitType fruit_type;
virtual bool Equals(Base *other) const = 0;
};
class Apple : public Base{
public:
Apple(int i): Base(FruitType::Apple), foo(i){}
int foo;
bool Equals(Base *other) const override {
if (other->fruit_type != FruitType::Apple)
return false;
return foo == ((Apple*)other)->foo;
}
};
class Orange : public Base{
public:
Orange(float f): Base(FruitType::Orange), bar(f){}
float bar;
bool Equals(Base *other) const override {
if (other->fruit_type != FruitType::Orange)
return false;
return bar == ((Orange*)other)->bar;
}
};
Then write your comparison function like this:
bool HasSameData(const Base* pCompare){
for (const Base *fruit : fruit_list_)
if (pCompare->Equals(fruit))
return true;
return false;
}
What I'm trying to achieve is to keep track of what types of objects we're created that inherit from a base class. If a class inherits from the base class but is not instantiated in an object I'm not that interested in tracking that (this condition can be included or not depending if the implementation is easier or not)
Dummy example:
template <typename T>
class Person
{
public:
Person() {
T* x;
container.push_back(x);
}
virtual ~Person() {}
private:
static heterogeneous_container container;
};
class Employee : public Person <Employee>
{
};
class Employee2 : public Employee
{
};
Also, I would like this to work for chained inheritance. Is it possible that when I instantiate an Employee2, the base class Person will add an Employee2 type pointer in the container?
As for the heterogeneous container, I think this can be used link
I think what you want is more like:
class Person
{
public:
Person() {
objects.push_back(this);
}
virtual ~Person() {
objects.erase(this);
}
private:
static std::set<const Person*> objects;
};
class Employee : public Person
{
};
class Employee2 : public Employee
{
};
With this approach, you can enquire the dynamic type of the most-derived object that each of the pointers in the container points to.
Note that the objects set has to contain the pointers, not the type_info for each object. The problem is that inside the constructor for the Person sub-object of an Employee2 object, the most-derived type of *this will be Person, not Employee2 (it won't become Employee2 until execution enters the Employee2 constructor).
More or less, I have somewhere working like that :
#include <iostream>
#include <functional>
#include <vector>
struct ClassEntry {
size_t id = 0;
const char* label;
};
class BaseClass {
public:
protected:
static void RegisterType(size_t id, const char * label) {
ClassEntry entry;
entry.id = id;
entry.label = label;
mRegisteredTypes.emplace_back(entry);
std::cout << "Registered type " << id << " label " << label << std::endl;
}
static size_t createId() {
static size_t id = 0;
return id++;
}
static std::vector<ClassEntry> mRegisteredTypes;
};
std::vector<ClassEntry> BaseClass::mRegisteredTypes;
class OneTimeCall {
public:
OneTimeCall(std::function<void(void)>&& func) {
func();
}
virtual ~OneTimeCall() {
}
};
template<typename T>
class MyClass : public BaseClass {
public:
MyClass() {
static OneTimeCall one_time {
[this]{
BaseClass::RegisterType(GetId(), T::GetType());
}
};
}
private:
protected:
static size_t GetId() {
static size_t id = BaseClass::createId();
return id;
}
};
class A : public MyClass<A> {
public:
A() {
}
static const char *GetType() {
return "ClassA";
}
};
class B : public MyClass<B> {
public:
B() {
}
static const char *GetType() {
return "ClassB";
}
};
int main() {
A a;
B b;
A a2;
B b2;
return 0;
}
The output is :
Registered type 0 label ClassA
Registered type 1 label ClassB
The main idea is to use CRTP and static initialization in construction for register each type only one time. It works without problems in linux, on windows compiler the static BaseClass ID is new on each DLL, so you need to tune a bit for use in a external library.
With this approach you dont need any external library and is possible to compile without rtti.
For inheritance you can create a new class:
template<typename Current, typename Base>
class Mix : public MyClass<Current>, public Base {};
So if you pass "type C" as current type (CRTP) and type A as base class can work.
class C : public Mix<C, A> {
public:
C() {
}
static const char *GetType() {
return "ClassC";
}
};
With this approach if you have previously registered "A" it will not be registered again, and if you dont have "A" it will be registered after "C".
One way to track objects is to store them an intrusive list and embed a link node into the objects. This provides noexcept guarantee for tracker operations and doesn't require an extra memory allocation when inserting the elements into the tracker container, for the price of an embedded list node (two pointers) in each tracked object:
#include <iostream>
#include <boost/intrusive/list.hpp>
namespace bi = boost::intrusive;
template<class T>
class Tracker : public bi::list_base_hook<bi::link_mode<bi::auto_unlink>>
{
protected:
static bi::list<Tracker, bi::constant_time_size<false>> objects_;
Tracker() noexcept { objects_.push_back(*this); }
Tracker(Tracker const&) noexcept { objects_.push_back(*this); }
public:
static auto count() noexcept { return objects_.size(); }
};
template<class T>
bi::list<Tracker<T>, bi::constant_time_size<false>> Tracker<T>::objects_;
struct Employee : Tracker<Employee> {};
struct Employee2 : Employee {};
int main() {
std::cout << Tracker<Employee>::count() << '\n';
{
Employee e0;
Employee2 e1;
std::cout << Tracker<Employee>::count() << '\n';
}
std::cout << Tracker<Employee>::count() << '\n';
}
Outputs:
0
2
0
Tracker without Boost library:
struct AutoListNode {
AutoListNode *next_ = this, *prev_ = this;
AutoListNode() noexcept = default;
AutoListNode(AutoListNode const&) = delete;
AutoListNode& operator=(AutoListNode const&) = delete;
~AutoListNode() noexcept { this->erase(); }
void push_back(AutoListNode* node) noexcept {
auto prev = prev_;
node->prev_ = prev;
node->next_ = this;
prev->next_ = node;
prev_ = node;
}
void erase() noexcept {
auto next = next_;
auto prev = prev_;
prev->next_ = next;
next->prev_ = prev;
}
size_t size() const noexcept {
size_t count = 0;
for(auto node = next_; node != this; node = node->next_)
++count;
return count;
}
};
template<class T>
class Tracker : private AutoListNode
{
protected:
static AutoListNode objects_;
Tracker() noexcept { objects_.push_back(this); }
Tracker(Tracker const&) noexcept { objects_.push_back(this); }
public:
static auto count() noexcept { return objects_.size(); }
};
template<class T>
AutoListNode Tracker<T>::objects_;
I've seen a number of posts regarding C++ factories, but so far I haven't seen a solution that solves my problem. (Though I may be missing something.)
Example console app:
#include <memory>
#include <map>
#include <iostream>
using namespace std;
class ResourceManager;
/// abstract base class
class Identity
{
public:
int Id() const { return _id; }
/// make this an abstract class
virtual ~Identity() = 0 {}
protected:
Identity() { _id = _nextId++; }
private:
int _id;
static int _nextId;
};
int Identity::_nextId = int();
/// derived classes
class Component : public Identity
{
friend class ResourceManager;
public:
~Component() { }
};
class Entity : public Identity
{
friend class ResourceManager;
public:
~Entity() { }
};
class ResourceManager
{
public:
template<typename T>
T& Create()
{
auto ptr = std::make_shared<T>();
auto id = ptr->Id();
_resources[id] = std::move(ptr);
return *dynamic_pointer_cast<T>(_resources[id]);
}
private:
std::map<int, std::shared_ptr<Identity>> _resources;
};
int main(int argc, char *argv[])
{
cout << "Factory test" << endl;
ResourceManager r;
auto& e = r.Create<Entity>();
cout << "e.id = " << e.Id() << endl;
Entity e2;
cout << "e2.id = " << e2.Id() << endl;
Component c;
cout << "c.id = " << c.Id() << endl;
std::getchar();
}
I need to make sure that only ResourceManager can instantiate Entity, Component and any classes that derive from them.
I've looked and adding ResourceManager as a friend class to Identity, and making the constructors private or protected, with no success. (This could be a blind alley, or just an implementation problem on my end.)
Any suggestions?
Update and Edit
Replaced code with compilable example. Although the constructor for Identity() is protected, I can still directly instantiate derived classes.
Following should work:
friend class ResourceManager; should be in each derivated classes.
(friend is not inherited).
class ResourceManager;
/// abstract base class
class Identity
{
public:
int Id() const { return _id; }
/// make this an abstract class
virtual ~Identity() = 0;
// Forbid any copy
Identity(const Identity&) = delete;
Identity(const Identity&&) = delete;
Identity& operator = (const Identity&) = delete;
Identity& operator = (Identity&&) = delete;
protected:
Identity() { _id = _nextId++; }
private:
int _id;
static int _nextId;
};
// empty destructor
Identity::~Identity() {}
int Identity::_nextId = 0;
/// derived classes
class Component : public Identity
{
friend class ResourceManager;
public:
~Component() { }
protected:
Component() = default;
};
class Entity : public Identity
{
friend class ResourceManager;
public:
~Entity() { }
protected:
Entity() = default;
};
class ResourceManager
{
public:
template<typename T>
T& Create()
{
std::unique_ptr<T> ptr(new T);
T& res = *ptr;
_resources[ptr->Id()] = std::move(ptr);
return res;
}
/// TODO: need to make sure that resource ID is actually of type T
/// and that _resources contains ID.
template<typename T>
T* Get(int id)
{
auto it = _resources.find(id);
if (it == _resources.end()) {
return nullptr;
}
return dynamic_cast<T*>(it->second.get());
}
private:
std::map<int, std::unique_ptr<Identity>> _resources;
};
Note that since ResourceManager owns the resource I change std::shared_ptr to std::unique_ptr.
I fixed ResourceManager::Get with invalid id.
Have you tried a protected construtor?
class Identity
{
friend class ResourceManager;
public:
int Id() { return _id; }
virtual ~Identity() = 0;
protected:
Identity() {
_id = _nextId++;
}
private:
static int _nextId;
// do not forget to put "int Identity::_nextId = 0;" in a source file
};
Identity::~Identity()
{
}
But you need to repeat this pattern in every derived class. Thus making ResourceManager a friend and making the constructor private or protected.
I have the following template classes,
I need to figure out how to implement a conversion operator between the derived template classes.
template<class T>
class Base
{
public:
Base () { }
template <class U>
operator Base<U>()
{
return Base<U> (v);
}
virtual double getV() = 0;
};
class D1: public Base<D1>
{
public:
D1(int j)
{
i = j;
}
double getV() const { return i; }
template <class U>
operator Base<U>()
{
return Base<U>(getV());
}
private:
int i;
};
class D2: public Base<D2>
{
public:
D2(int j)
{
i2 = j;
}
double getV() const { return i2; }
template <class U>
operator Base<U>()
{
return Base<U>(getV());
}
private:
int i2;
};
How can I achieve the following?
D1 d1(3);
D2 d2 = d1; //conversion from 'D1' to non-scalar type 'D2' requested
if the design itself sound or should I be doing something else?
Please let me know what ur thoughts
In your example, I don't see a reason why CRTP is used.
The specializations of Base all have a virtual member function that is not dependent on the template parameter. Your code suggests this virtual member function can be used to access all data necessary to create an instance of any class derived from a specialization of Base. If we follow this assumption, one could rather think of:
class Base
{
public:
virtual double getV() const = 0;
};
class D1 : public Base
{
int i;
public:
D1(int);
virtual double getV() const { return i; }
};
class D2 : public Base
{
int i;
public:
D2(int);
virtual double getV() const { return i; }
};
This still does not allow conversions. However, it is quite simple to add them here:
class D1 : public Base
{
int i;
public:
D1(int);
D1(Base const& p) : D1(p.getV()) {}
virtual double getV() const { return i; }
};
This conversion should be allowed by D1 and not by Base, because only D1 knows what data is required for it to be constructed.
If CRTP is necessary for things not shown here, you could still use a common base class:
class Common_base
{
public:
virtual double getV() const = 0;
};
template<class T>
class Base : public Common_base
{
};
class D1 : public Base<D1>
{
int i;
public:
D1(int);
D1(Common_base const& p) : D1(p.getV()) {}
virtual double getV() const { return i; }
};
If, for some reason, the CRTP is required for the conversion, you could still use a converting constructor template:
template<class T>
class Base
{
public:
virtual double getV() const = 0; // whyever
};
class D1 : public Base
{
int i;
public:
D1(int);
template<class U>
D1(Base<U> const& p) : D1(p.getV()) {}
virtual double getV() const { return i; }
};
It's hard to tell what you are trying to do but I don't think you can do it as described.
If you really want to have a common interface, you need to declare a common base class that includes all the methods and properties that your code needs, and have both classes derive from that. You can then always cast to the base class.
This seems ideal in fact. Especially since you can always use virtual methods to customize behavior in the base class if needed.
If that doesn't work within your current task, perhaps you should talk more about why you need this.
You either write a constructor for D2 that takes a const D1& or you write a conversion operator in D1 that returns a D2. You have to decide what it means to do this conversion and implement the conversion appropriately.
You can add a constructor in your derived classes that takes a Base template :
template <class U>
D2(const Base<U> &other)
{
i2 = other.getV();
}
But not sure if it will fit your needs.
In C++, I have a class A, and a class B.
In class A, there is a object (of class B) , I want to change the class A member data in the object of class B. How can I do that ?
I want to do this:
class A {
public:
A() {
new B(this);
}
private:
int i;
};
class B {
public:
B(A* parent) {
this->parent = parent;
}
change() {
parent->i = 5;
}
private:
A* parent;
};
In declaration of class A you need to define class B as a friend:
friend class B;
Rather than setting B as a friend class to A, a better method to preserve encapsulation would be to add a setter method to class A.
Your class A would then look somewhat like this:
class A {
public:
A() {
new B(this);
}
void set_i(int value)
{
i = value;
}
private:
int i;
};
Then in your class B implementation, call set_i().
class B {
public:
B(A* parent) {
this->parent = parent;
}
change() {
parent->set_i(5);
}
private:
A* parent;
};
This way you're not exposing and relying on private implementation details of class A in class B.
class A {
friend class B;
private:
int i;
public:
A() : i(0) {
new B(this);
}
};