Pass constructor arguments to member object - c++

I am sure this question has been answered before, but I am unable to find a satisfactory answer. Take the following example:
class A {
public:
A(int a, int b, int c);
//...
};
class B {
public:
B(...);
private:
A _a0;
A _a1;
A _a2;
A _a3;
};
Class B contains multiple instances of class A. I want to represent that B "owns" all of these instances. From what I know, there are a couple ways to represent this
The instances of A are declare as direct members of B (as I have shown), and thus the memory of the A instances is directly inside the B class.
B contains a bunch of unique_ptr objects to the A classes
Use the Builder design pattern to do the creation on step at a time
The reason I don't want to use (2) and (3) is that I want NO heap allocation of these objects (I am writing for an embedded system).
The problem with (1) is, since each A requires 3 constructor parameters and these parameters are not provided by B but rather by the application writer (i.e., B merely owns and uses these instances of A but does not need to know how to create them), I have the bad option of passing 12 arguments to the constructor of B in order to create all 4 As.
I am wondering if another option would be to write the constructor of B such that it takes r-values to As and then move these As into B?
For example:
class B {
public:
B(A&& a0, A&& a1, A&& a2, A&& a3) :
_a0(std::move(a0)),
_a1(std::move(a1)),
_a2(std::move(a2)),
_a3(std::move(a3))
{
}
private:
A _a0;
A _a1;
A _a2;
A _a3;
};
The one problem I can see which this solution is, what if A is a class which points/refers to some "global" resource. The constructor of A should initialize this resource and the destructor should de-initialize this resource. If A is moved, the reference/pointer to the resource also has to be moved AND the old copy of A has to be placed in some valid state which does not de-initialize the resource because ownership has been transferred. What would be the correct way to represent this?

So, your main problem is designing class A. From your description looks like it should be non-copyable, but move-constructible (and move-assignable):
The one problem I can see which this solution is, what if A is a class
which points/refers to some "global" resource. The constructor of A
should initialize this resource and the destructor should
de-initialize this resource. If A is moved, the reference/pointer to
the resource also has to be moved AND the old copy of A has to be
placed in some valid state which does not de-initialize the resource
because ownership has been transferred.
The usual way to create such a class is by using unique_ptr with a custom deleter. Suppose, you have class Resource and
Resource* init_resource(int a);
void deinit_resource(Resource*);
Then, your class A may look like:
class A {
public:
A(int a, int b, int c)
: r( init_resource(a) )
{
//...
}
private:
std::unique_ptr<Resource, deinit_resource> r;
//...
};
With this class A, your constructor design of class B will work, but this is not the only way. If you like Builder pattern but cannot use dynamic memory, then std::optional is your friend. For example:
class B
{
public:
B(){}
void set_A1(int a, int b, int c)
{
a1_ = A(a, b, c);
}
//...
private:
std::optional<A> a1_;
//...
};

Here is a solution I put together that seems to work correctly
#include <assert.h>
#include <utility>
#include <cstdint>
#include <iostream>
#include <atomic>
/*
* Some global resource
* On an embedded system, this would be the peripherals/special-purpose registers
*/
static unsigned int resource1 = 0;
static unsigned int resource2 = 0;
/*
* Often, an SDK for an MCU will provide #define statements which contain the
* the start address (as an integer) of the peripheral register(s)
*/
#define RESOURCE1_ADDR (std::intptr_t)(&resource1)
#define RESOURCE2_ADDR (std::intptr_t)(&resource2)
template <typename T>
class ResourceManager;
/**
* #brief A handle to a particular resource managed by a ResourceManager
* #note Similar to unique_ptr, a ResourceHandle may only be moved
*/
template <typename T>
class ResourceHandle {
public:
~ResourceHandle() {
std::cout << "ResourceHandle::~ResourceHandle()" << std::endl;
}
/**
* #brief Helper method to release the resource managed by this handle back
* to its appropriate resource manager.
*/
inline void release() {
assert(_addr != 0);
_manager.release(std::move(*this));
}
/**
* #brief Copy constructor
* #note Deleted because ResourceHandle is move-only
*/
ResourceHandle(const ResourceHandle& other) = delete;
/**
* #brief Assignment operator
* #note Deleted because ResourceHandle is move-only
*/
const ResourceHandle& operator=(const ResourceHandle&) = delete;
ResourceHandle(ResourceHandle&& other) :
_manager(other._manager),
_addr(other._addr)
{
std::cout << "ResourceHandle::ResourceHandle(ResourceHandle&&)" << std::endl;
assert(_addr != 0);
other._addr = 0;
}
ResourceHandle& operator=(ResourceHandle&& other) {
std::cout << "ResourceHandle::operator=(ResourceHandle&&)" << std::endl;
if (this != &other) {
_addr = other._addr;
other._addr = 0;
}
return *this;
}
operator T*() const {
assert(_addr != 0);
return reinterpret_cast<T*>(_addr);
}
T* operator->() const { return operator T*(); }
inline bool isValid() const { return _addr != 0; }
protected:
ResourceHandle(ResourceManager<T>& manager, std::intptr_t addr) :
_manager(manager),
_addr(addr)
{
std::cout << "ResourceHandle::ResourceHandle(ResourceManager<T>&, std::intptr_t)" << std::endl;
}
private:
ResourceManager<T>& _manager;
/**
* #brief The integer address of the resource being mamaged by this handle
* #note Set to 0 when invalid
*/
std::intptr_t _addr;
friend class ResourceManager<T>;
};
/**
* #brief Class which manages a particular resource by allowing a ResourceHandle
* to be "obtained" and "released"
*/
template <typename T>
class ResourceManager {
public:
constexpr ResourceManager(std::intptr_t addr) :
_resource(*this, addr)
{
}
constexpr ResourceHandle<T> obtain() {
std::cout << "ResourceHandle::obtain()" << std::endl;
assert(_resource.isValid());
return std::move(_resource);
}
constexpr void release(ResourceHandle<T> r) {
std::cout << "ResourceHandle::release()" << std::endl;
assert(!_resource.isValid());
_resource = std::move(r);
}
private:
ResourceHandle<T> _resource;
};
/**
* #brief Example class which "uses" (i.e., takes ownership of) a resource
* via a ResourceHandle
*/
class ResourceUser {
public:
ResourceUser(ResourceHandle<unsigned int> r) :
_r(std::move(r))
{
std::cout << "ResourceUser::ResourceUser(ResourceHandle<unsigned int>)" << std::endl;
//Init
std::cout << "ResourceUser -> Init resource" << std::endl;
*_r = 0;
}
~ResourceUser() {
std::cout << "ResourceUser::~ResourceUser()" << std::endl;
if (_r.isValid()) {
std::cout << "ResourceUser -> Cleanup resource" << std::endl;
*_r = 0;
_r.release();
}
}
ResourceUser(ResourceUser&& other) :
_r(std::move(other._r))
{
std::cout << "ResourceUser::ResourceUser(ResourceUser&&)" << std::endl;
}
void set(unsigned int x) {
std::cout << "ResourceUser::set()" << std::endl;
*_r = x;
}
private:
ResourceHandle<unsigned int> _r;
};
/**
* #brief Example class which "owns" two ResourceUser objects
*/
class ResourceUserUser {
public:
ResourceUserUser(ResourceUser&& a, ResourceUser&& b) :
_a(std::move(a)),
_b(std::move(b))
{
std::cout << "ResourceUserUser::ResourceUserUser()" << std::endl;
}
~ResourceUserUser() {
std::cout << "ResourceUserUser::~ResourceUserUser()" << std::endl;
}
void foo() {
std::cout << "ResourceUserUser::foo()" << std::endl;
_a.set(10);
_b.set(20);
}
private:
ResourceUser _a;
ResourceUser _b;
};
class Resource1 : public ResourceManager<unsigned int> {
public:
inline static ResourceManager<unsigned int>& instance() { return _instance; }
private:
static ResourceManager<unsigned int> _instance;
};
class Resource2 : public ResourceManager<unsigned int> {
public:
inline static ResourceManager<unsigned int>& instance() { return _instance; }
private:
static ResourceManager<unsigned int> _instance;
};
ResourceManager<unsigned int> Resource1::_instance(RESOURCE1_ADDR);
ResourceManager<unsigned int> Resource2::_instance(RESOURCE2_ADDR);
void test1() {
std::cout << std::endl << "BEGIN test1()" << std::endl;
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
ResourceUser user(Resource1::instance().obtain());
user.set(20);
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
std::cout << "END test1()" << std::endl;
}
void test2() {
std::cout << std::endl << "BEGIN test2()" << std::endl;
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
ResourceUserUser user(ResourceUser{Resource1::instance().obtain()}, ResourceUser{Resource2::instance().obtain()});
user.foo();
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
std::cout << "END test2()" << std::endl;
}
void test3() {
std::cout << std::endl << "BEGIN test3()" << std::endl;
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
ResourceUser user1(Resource1::instance().obtain());
ResourceUserUser user2(ResourceUser{Resource1::instance().obtain()}, ResourceUser{Resource2::instance().obtain()});
user2.foo();
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
std::cout << "END test3()" << std::endl;
}
If you execute test2() the output is
ResourceHandle::ResourceHandle(ResourceManager<T>&, std::intptr_t)
ResourceHandle::ResourceHandle(ResourceManager<T>&, std::intptr_t)
BEGIN test2()
resource1 = 0
resource2 = 0
ResourceHandle::obtain()
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceUser::ResourceUser(ResourceHandle<unsigned int>)
ResourceUser -> Init resource
ResourceHandle::obtain()
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceUser::ResourceUser(ResourceHandle<unsigned int>)
ResourceUser -> Init resource
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceUser::ResourceUser(ResourceUser&&)
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceUser::ResourceUser(ResourceUser&&)
ResourceUserUser::ResourceUserUser()
ResourceUser::~ResourceUser()
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceUser::~ResourceUser()
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceUserUser::foo()
ResourceUser::set()
ResourceUser::set()
resource1 = 10
resource2 = 20
END test2()
ResourceUserUser::~ResourceUserUser()
ResourceUser::~ResourceUser()
ResourceUser -> Cleanup resource
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceHandle::release()
ResourceHandle::operator=(ResourceHandle&&)
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceUser::~ResourceUser()
ResourceUser -> Cleanup resource
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceHandle::release()
ResourceHandle::operator=(ResourceHandle&&)
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
I am curious though, is there any way I can get rid of those extra calls to the move constructor? For example, the ResourceManager calls the move constructor to move the handle out of itself, then the ResourceUser calls the move constructor again.

Related

Are all the memory Dynamically Allocated by "new" being properly cleared in the following implementation

I am in a situation where I need to create a collection of classes which perform computations over Eigen Matrices. The original code is quiet big and complex to explain, so I have implemented a simplified version to explain my problem. I have written the following piece of code. Basically, I need to create a collection of different types of class objects. I plan to achieve this by using a baseClass which is extended by all the classes that need to be part of the collection. A second class named classIterator contains a vector named "classItr" that can store baseClass pointers. The child classes override and implement a function declared in base that is responsible for performing the computations. I delete all the object pointers in classItr using "delete", at the destructor of classIterator. What I want to know is first, whether this implementation is correct and safe and that all the memory allocated by "new" is being freed at the class destructors and second, if there is better and safer way to achieve the same.
The code
#include <iostream>
#include <vector>
#include <Core>
using namespace Eigen;
class baseClass
{
public:
MatrixXd m1;
MatrixXd m2;
std::string childName;
baseClass(std::string childName)
{
this->childName = childName;
std::cout << "\n Base Constructor. Child Name : " << this->childName << std::endl;
}
virtual ~baseClass()
{
std::cout << "\n Base Destructor. Child Name : " << this->childName << std::endl;
}
template<typename inputType_1, typename inputType_2>
void onSetData(MatrixBase<inputType_1> const & mat1, MatrixBase<inputType_2> const & mat2)
{
this->m1 = mat1;
this->m2 = mat2;
}
template<typename inputType_1>
void operator ()(MatrixBase<inputType_1> const & someMat)
{
/*
Some Code Involving "someMat" matrix.
*/
// Calling the child class implementation of the function.
someComputation();
}
virtual void someComputation() = 0;
};
class firstChild : public baseClass
{
public:
firstChild() : baseClass("firstChild")
{
std::cout << "\n First Child Constructor" << std::endl;
}
~firstChild()
{
std::cout << "\n First Child Destructor" << std::endl;
this->m1.resize(0, 0);
this->m2.resize(0, 0);
}
void someComputation() override
{
// Some Computation Using Base classes m1 and m2 go here.
std::cout << "\n First Child M1 : \n" << this->m1 << "\n M2 : \n" << this->m2 << std::endl;
}
};
class secondChild : public baseClass
{
public:
secondChild() : baseClass("secondChild")
{
std::cout << "\n Second Child Constructor" << std::endl;
}
~secondChild()
{
std::cout << "\n Second Child Destructor" << std::endl;
this->m1.resize(0, 0);
this->m2.resize(0, 0);
}
void someComputation() override
{
// Some Computation Using Base classes m1 and m2 go here.
std::cout << "\n Second Child M1 : \n" << this->m1 << "\n M2 : \n" << this->m2 << std::endl;
}
};
class classIterator
{
public:
std::vector< baseClass *> classItr;
classIterator()
{
std::cout << "\n Iterator Constructor" << std::endl;
}
~classIterator()
{
std::cout << "\n Iterator Destructor" << std::endl;
for (auto * tLayer : this->classItr) { delete tLayer; }
}
template< typename T >
void onAddClass(T classObj)
{
this->classItr.push_back(classObj);
}
template<typename inputType_1>
void onWork(MatrixBase<inputType_1> const & someMat)
{
for (auto * tLayer : this->classItr) { tLayer->operator()(someMat); }
}
};
classIterator onCreateIterator()
{
classIterator clsItr;
baseClass * obj1 = new firstChild();
baseClass * obj2 = new secondChild();
MatrixXd o1_m1 = MatrixXd::Random(3, 4);
MatrixXd o1_m2 = MatrixXd::Random(3, 4);
MatrixXd o2_m1 = MatrixXd::Random(2, 4);
MatrixXd o2_m2 = MatrixXd::Random(2, 4);
obj1->onSetData(o1_m1, o1_m2);
obj2->onSetData(o2_m1, o2_m2);
clsItr.onAddClass(obj1);
clsItr.onAddClass(obj2);
return clsItr;
}
int main()
{
if (true)
{
MatrixXd someMat = MatrixXd::Random(4, 3);
classIterator clsItr = onCreateIterator();
clsItr.onWork(someMat);
}
}

C++ : custom vtable implementation does not work

I'm trying to implement a custom vtable to better understand a concept of virtual tables and overriding. For this I have the following 'base' class
#pragma once
#include <iostream>
#include <string>
using namespace std::string_view_literals;
struct vtable;
class IdentityDocument {
public:
IdentityDocument()
: vtable_ptr_(&IdentityDocument::VTABLE),
unique_id_(++unique_id_count_)
{
std::cout << "IdentityDocument::Ctor() : "sv << unique_id_ << std::endl;
}
~IdentityDocument() {
--unique_id_count_;
std::cout << "IdentityDocument::Dtor() : "sv << unique_id_ << std::endl;
}
IdentityDocument(const IdentityDocument& other)
: vtable_ptr_(other.vtable_ptr_),
unique_id_(++unique_id_count_)
{
std::cout << "IdentityDocument::CCtor() : "sv << unique_id_ << std::endl;
}
IdentityDocument& operator=(const IdentityDocument&) = delete;
void PrintID() const {
std::cout << "IdentityDocument::PrintID() : "sv << unique_id_ << std::endl;
}
static void PrintUniqueIDCount() {
std::cout << "unique_id_count_ : "sv << unique_id_count_ << std::endl;
}
int GetID() const {
return unique_id_;
}
private:
vtable* vtable_ptr_ = nullptr;
static int unique_id_count_;
static vtable VTABLE;
int unique_id_;
};
struct vtable
{
void (IdentityDocument::* const PrintID)() const;
vtable (
void (IdentityDocument::* const PrintID)() const
) : PrintID(PrintID) {}
};
int IdentityDocument::unique_id_count_ = 0;
vtable IdentityDocument::VTABLE = {&IdentityDocument::PrintID};
And here is another class that must override PrintId method
#pragma once
#include "identity_document.h"
#include <iostream>
#include <string>
#include <ctime>
using namespace std::string_view_literals;
class Passport {
public:
Passport()
: expiration_date_(GetExpirationDate())
{
IdentityDocument* base_ptr = reinterpret_cast<IdentityDocument*>(this);
vtable* vtable_ptr = reinterpret_cast<vtable*>(base_ptr);
vtable_ptr = &Passport::VTABLE;
std::cout << "Passport::Ctor()"sv << std::endl;
}
Passport(const Passport& other)
: identity_(other.identity_)
, expiration_date_(other.expiration_date_)
{
IdentityDocument* base_ptr = reinterpret_cast<IdentityDocument*>(this);
vtable* vtable_ptr = reinterpret_cast<vtable*>(base_ptr);
vtable_ptr = &Passport::VTABLE;
std::cout << "Passport::CCtor()"sv << std::endl;
}
~Passport() {
std::cout << "Passport::Dtor()"sv << std::endl;
}
void PrintID() const {
std::cout << "Passport::PrintID() : "sv << identity_.GetID();
std::cout << " expiration date : "sv << expiration_date_.tm_mday << "/"sv << expiration_date_.tm_mon << "/"sv
<< expiration_date_.tm_year + 1900 << std::endl;
}
void PrintVisa(const std::string& country) const {
std::cout << "Passport::PrintVisa("sv << country << ") : "sv << identity_.GetID() << std::endl;
}
private:
IdentityDocument identity_;
const struct tm expiration_date_;
static vtable VTABLE;
tm GetExpirationDate() {
time_t t = time(nullptr);
tm exp_date = *localtime(&t);
exp_date.tm_year += 10;
mktime(&exp_date);
return exp_date;
}
};
vtable Passport::VTABLE = {reinterpret_cast<void (IdentityDocument::*)() const>(&Passport::PrintID)};
And a short demo :
int main() {
array<IdentityDocument*, 1> docs = { (IdentityDocument*)(new Passport()) };
for (const auto* doc : docs) {
doc->PrintID();
}
}
Unfortunately, I see that the 'derived' method was not called. Am I using a wrong approach to implement a vtable concept?
Am I using a wrong approach to implement a vtable concept?
Yes. You have not written any code that reads your vtable, and the C++ compiler will not generate any code to read your vtable either.
When you declare a member function virtual, your compiler needs to call that function in a special way. Any call to that function should be looked up in a vtable.
When a member function is not virtual, your compiler knows that it doesn't need to look up the location of the function. It knows which function to call. No lookup needed.
In your code, you have created a vtable, but this line, calling a non-virtual function:
doc->PrintID();
Does not need a vtable, and does not check for one.
doc is an IdentityDocument*, so doc->PrintID() calls IdentityDocument::PrintID(). No lookup required, no lookup happens.
Finally I simplified my solution and got what I wanted :
#include <iostream>
class A;
struct VTable
{
void (*say_hello)(A*);
};
class A
{
public:
A()
{
vtable.say_hello = A::sayHello;
}
void sayHello()
{
vtable.say_hello(this);
}
static void sayHello(A* a)
{
std::cout << "A::sayHello" << std::endl;
}
VTable vtable;
};
class B
{
public:
B()
{
a.vtable.say_hello = B::sayHello;
}
void sayHello()
{
a.vtable.say_hello((A*)this);
}
static void sayHello(A* a)
{
std::cout << "B::sayHello\n" << std::endl;
}
private:
A a;
};
int main()
{
A* a = (A*)(new B);
a->sayHello();
delete a;
}

How to return the member of template derived class from base?

Is it possible to return a template member of a derived class by the base?
Please find the following classes:
Data.h:
#include <string>
class IData{
public:
virtual ~IData(){};
virtual const std::string& getName() const = 0;
};
template <typename T>
class DataImpl: public IData
{
public:
DataImpl(const std::string& name, T* ptrToData)
:_name(name)
,_ptrToData(ptrToData)
{};
~DataImpl(){};
const std::string& getName() const
{
return _name;
}
const T* getDataPtr() const
{
return _ptrToData;
}
private:
std::string _name;
T* _ptrToData; // <-- how to return this pointer ?
};
Component.h:
#include <vector>
#include <string>
#include "Data.h"
class Component
{
public:
Component(const std::string& name)
:_name(name)
{};
~Component(){};
const std::string& getName() const
{
return _name;
};
std::vector<IData*>& getDataList()
{
return _dataList;
};
void addData(IData* ptr)
{
_dataList.push_back(ptr);
};
private:
std::string _name;
std::vector<IData*> _dataList;
};
main.cpp:
#include <iostream>
#include <vector>
#include <string>
#include "Component.h"
#include "Data.h"
int main()
{
// primitive types
int x = 5;
float y = 5.7;
bool b = false;
// complex structures
struct complex{
int a;
std::string c;
};
complex cx;
cx.a = 5;
cx.c = "anything";
DataImpl<int> d1("x", &x);
DataImpl<float> d2("y", &y);
DataImpl<bool> d3("b", &b);
DataImpl<complex> d4("complex", &cx);
Component cmp("cmpName");
cmp.addData(&d1);
cmp.addData(&d2);
cmp.addData(&d3);
cmp.addData(&d4);
std::vector<IData*>::iterator it = cmp.getDataList().begin();
for (;it != cmp.getDataList().end(); ++it)
{
IData* ptr = *it;
std::cout << ptr->getName() << std::endl;
}
return 0;
}
Inside the loop in the main.cpp, I was accessing every DataImpl member. But I want to return/get the member variable T* _ptrToData through the base class IData but so far I did not find any way.
I have a compiler restriction to c++98
Thanks in advance.
You can try to use dynamic_cast to perform a type-safe downcast of the IData* pointer back to the pointer of the derived class (e.g. DataImpl<int>* ) . However, this may require the Run-time type information (RTTI) of the compiler enabled.
Here's an example:
for (;it != cmp.getDataList().end(); ++it)
{
IData* ptr = *it;
std::cout << ptr->getName() << std::endl;
DataImpl<int>* pInt = dynamic_cast<DataImpl<int>*>(ptr);
if (pInt) {
std::cout << "*pInt->getDataPtr(): " << *pInt->getDataPtr() << std::endl;
std::cout << "pInt->getDataPtr(): " << pInt->getDataPtr() << std::endl;
}
DataImpl<float>* pfloat = dynamic_cast<DataImpl<float>*>(ptr);
if (pfloat) {
std::cout << "*pfloat->getDataPtr(): " << *pfloat->getDataPtr() << std::endl;
std::cout << "pfloat->getDataPtr(): " << pfloat->getDataPtr() << std::endl;
}
DataImpl<bool>* pbool = dynamic_cast<DataImpl<bool>*>(ptr);
if (pbool) {
std::cout << "*pbool->getDataPtr(): " << *pbool->getDataPtr() << std::endl;
std::cout << "pbool->getDataPtr(): " << pbool->getDataPtr() << std::endl;
}
}

Static_cast converts to wrong data type, but the result is still correct?

Based on the comments to my last question (Getter-function for derived class in derived class, when using pointer to base class), I've been told that I have to use static_cast when recasting my pointer from the base class to the derived class, in order to access the derived class. I tested that using the following code:
#include <iostream>
class class_data{
public:
int val_a = 0;
double val_b = 0.;
};
class overridden_class_data : public class_data{
public:
int val_c = 0.;
};
class overridden_class_data_II : public class_data{
public:
int val_c = 12.;
};
class BaseClass{
public:
BaseClass(){};
virtual void print_data() = 0;
virtual class_data *get_local_data() = 0;
class_data local_class_data;
};
class DerivedClass : public BaseClass{
public:
DerivedClass(){
local_class_data.val_a = 10;
local_class_data.val_b = 100.;
local_class_data.val_c = 14;
};
void print_data() override{
std::cout << "Hello World\n";
}
class_data * get_local_data() override {
return &local_class_data;
}
overridden_class_data local_class_data;
};
class DerivedClassII : public BaseClass{
public:
DerivedClassII(){
local_class_data.val_a = 10;
local_class_data.val_b = 100.;
};
void print_data() override{
std::cout << "Hello World\n";
}
class_data * get_local_data() override {
return &local_class_data;
}
overridden_class_data_II local_class_data;
};
void test_func(BaseClass *class_pointer){
std::cout << class_pointer->get_local_data()->val_a << '\n';
std::cout << class_pointer->local_class_data.val_a << '\n';
class_pointer->local_class_data.val_a = 5;
std::cout << class_pointer->local_class_data.val_a << '\n';
std::cout << class_pointer->get_local_data()->val_a << '\n';
class_pointer->get_local_data()->val_a = 15;
std::cout << class_pointer->local_class_data.val_a << '\n';
std::cout << class_pointer->get_local_data()->val_a << '\n';
std::cout << static_cast<overridden_class_data*>(class_pointer->get_local_data())->val_c << '\n';
}
int main(void){
std::cout << "From main\n";
DerivedClass DClass;
DerivedClassII EClass;
std::cout << "DClass: \n";
test_func(&DClass);
std::cout << "EClass: \n";
test_func(&EClass);
return 0;
}
Here I have two derived classes, which use two different derived classes as class variable. To access the data of those classes I have to use static_cast onto the returned base-class pointer to cast it back to the derived class. Still, I do not want to rewrite the function test_func() for both classes, but instead use the same function for them.
Initially, I thought that I had to write the last line of the function twice, recasting the class variable pointer once to overridden_class_data* and once to overridden_class_data_II*, depending on the input class. But after testing I noticed that I do not have to do that, I can recast it to overridden_class_data*, but it still acts as if I recasted it overridden_class_data_II*. Why? Is it because both classes contain the same elements, and therefore the pointer can point to the same spot?
As for your original question, yes this is happening just because (1) the data members of your class are identically setup and (2) static_cast is not safe for such polymorphic casts.
A simple counterexample to break test_func would be(code):
class overridden_class_data : public class_data{
public:
int val_pad = 0.;
int val_c = 23.;
};
which would incorrectly then print the value 0 instead of 12 for the EClass pointer->get_local_data()->val_c.
A few ways you could go about solving this(making test_fn single use):
Correctly detect the above issue using dynamic_casts, but then test_func would need to be called with appropriate explicit template args.
Forego the casts with compile time safety by making a simple generic test_func and using covariant return types. You mentioned that your concerned about too many templates - Is it code bloat you are worried about?
#churill suggestion of using a virtual getter like get_val_c.
Here is the snippet for the 2nd method suggested - I've marked the changes I made(code):
#include <iostream>
class class_data{
public:
int val_a = 0;
double val_b = 0.;
};
class overridden_class_data : public class_data{
public:
int val_pad = 23;
int val_c = 0.;
};
class overridden_class_data_II : public class_data{
public:
int val_c = 12.;
};
class BaseClass{
public:
BaseClass(){};
virtual void print_data() = 0;
virtual class_data *get_local_data() = 0;
class_data local_class_data;
};
class DerivedClass : public BaseClass{
public:
DerivedClass(){
local_class_data.val_a = 10;
local_class_data.val_b = 100.;
local_class_data.val_c = 14;
};
void print_data() override{
std::cout << "Hello World\n";
}
// use covariant return type
overridden_class_data * get_local_data() override {
return &local_class_data;
}
overridden_class_data local_class_data;
};
class DerivedClassII : public BaseClass{
public:
DerivedClassII(){
local_class_data.val_a = 10;
local_class_data.val_b = 100.;
};
void print_data() override{
std::cout << "Hello World\n";
}
// use covariant return type
overridden_class_data_II * get_local_data() override {
return &local_class_data;
}
overridden_class_data_II local_class_data;
};
template <typename T>
void test_func(T *class_pointer){ // make generic
std::cout << class_pointer->get_local_data()->val_a << '\n';
std::cout << class_pointer->local_class_data.val_a << '\n';
class_pointer->local_class_data.val_a = 5;
std::cout << class_pointer->local_class_data.val_a << '\n';
std::cout << class_pointer->get_local_data()->val_a << '\n';
class_pointer->get_local_data()->val_a = 15;
std::cout << class_pointer->local_class_data.val_a << '\n';
std::cout << class_pointer->get_local_data()->val_a << '\n';
std::cout << class_pointer->get_local_data()->val_c << '\n';
}
int main(void){
std::cout << "From main\n";
DerivedClass DClass;
DerivedClassII EClass;
std::cout << "DClass: \n";
test_func(&DClass);
std::cout << "EClass: \n";
test_func(&EClass);
return 0;
}

Cocos2dx Style and Implementation

I'm sort of getting back into cocos2dx development. This time I would like to fully understand the subtleties of the library. I have begun to get a good understanding of singleton classes, which they use throughout. I do have a question about their implementation. Here is a basic example of a singleton class being used
class GlobalClass
{
int m_value;
public:
GlobalClass(int v = 0)
{
m_value = v;
}
int get_value()
{
return m_value;
}
void set_value(int v)
{
m_value = v;
}
};
// Default initialization
GlobalClass *global_ptr = 0;
void foo(void)
{
// Initialization on first use
if (!global_ptr)
global_ptr = new GlobalClass;
global_ptr->set_value(1);
cout << "foo: global_ptr is " << global_ptr->get_value() << '\n';
}
void bar(void)
{
if (!global_ptr)
global_ptr = new GlobalClass;
global_ptr->set_value(2);
cout << "bar: global_ptr is " << global_ptr->get_value() << '\n';
}
int main()
{
if (!global_ptr)
global_ptr = new GlobalClass;
cout << "main: global_ptr is " << global_ptr->get_value() << '\n';
foo();
bar();
}
My question is about the initialization that comes after class definition and before foo, bar, and main. Essentially, I am interested in this line
GlobalClass *global_ptr = 0;
Where is the stack instance being initialized? You need some interface for that global pointer to the heap that is the member of that stack instance, right? If so, where is this done in cocos2dx?
My other question is about the use of the scope resolution operator (::) to call methods such as in
glview = GLViewImpl::create("MyView")
What purpose does this serve? Is this to overstep name spacing to access singleton instances?
If any of my understandings are wrong, especially on singletons, please correct them.
I think Syntax of your Singleton class is wrong.
It should be like this :
class GlobalClass
{
static GlobalClass* _instance; // Make private so only can access with method to avoid NPE for first time access
GlobalClass(int v = 0) // Make constructor private, you can't create object outside the class
{
m_value = v;
}
int m_value;
public:
static GlobalClass* getInstance();
int get_value()
{
return m_value;
}
void set_value(int v)
{
m_value = v;
}
};
GlobalClass* GlobalClass::_instance = 0;
GlobalClass* GlobalClass::getInstance() {
return GlobalClass::_instance == nullptr ? GlobalClass::_instance = new GlobalClass : GlobalClass::_instance;
}
void foo(void)
{
auto global_ptr = GlobalClass::getInstance();
global_ptr->set_value(1);
std::cout << "foo: global_ptr is " << global_ptr->get_value() << '\n';
}
void bar(void)
{
auto global_ptr = GlobalClass::getInstance();
global_ptr->set_value(2);
std::cout << "bar: global_ptr is " << global_ptr->get_value() << '\n';
}
int main()
{
auto global_ptr = GlobalClass::getInstance();
std::cout << "main: global_ptr is " << global_ptr->get_value() << '\n';
foo();
bar();
system("pause");
return 0;
}
And your second question :
Why we use or having static method create() almost in all class of cocos2d-x
In cocos2d-x we create object in two phase
- Create Object // No game Logic only set default_values
- Initialize Object
We're using Reference Count mechanism for memory management in cocos2d-x. what is it ?
These 2-phase constructor and auto-released reference count together into a static function: create()