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()
Related
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.
Here is a demo code snippet(https://godbolt.org/z/31Tq3r):
#include<iostream>
class Ctx
{
public:
enum RUN_MOD
{
MOD_RT,
MOD_NRT,
};
Ctx(RUN_MOD runType)
{
if(runType == MOD_RT)
{
Ctx();
}
}
Ctx()
{
m_L = malloc(100);
std::cout << "set m_L=" << m_L << std::endl;
}
void print()
{
std::cout <<"print() m_L=" << m_L << std::endl;
}
private:
void *m_L;
const char* const ARG_TYPE_NOT_MATCH = "the type of argument is not match";
const char* const ARG_NUM_INVALID = "the number of arguments is invalid";
const char* const STACK_OPS_INPUT_ARG_INVALID = "the input argument passed to the stack ops is invalid";
};
int main()
{
Ctx ctx(Ctx::RUN_MOD::MOD_RT);
ctx.print();
}
Here are outputs when invoking the binary program on Ubuntu:
set m_L=0x614c20
print() m_L=0x400ad0
You see the addresses are not the same. I have set m_L by invoking Ctx::Ctx()(which is called by Ctx::Ctx(RUN_MOD runType)) indeed. I am really confused.
Constructor delegation can only be used from inside a constructor’s member initialization list, NOT inside a constructor’s body. This answer shows how to avoid the need to use constructor delegation at all, by creating a common initialization function that multiple constructors can then call as needed.
However, if you did want to use constructor delegation, for whatever reason, then in this case the Ctx() constructor should delegate to the Ctx(RUN_MOD) constructor, not the other way around as you originally attempted, eg:
class Ctx
{
public:
enum RUN_MOD
{
MOD_RT,
MOD_NRT,
};
Ctx(RUN_MOD runType)
{
if (runType == MOD_RT)
{
m_L = malloc(100);
std::cout << "set m_L=" << m_L << std::endl;
}
}
Ctx() : Ctx(MOD_RT) // <— here
{
}
void print()
{
std::cout << "print() m_L=" << m_L << std::endl;
}
private:
void *m_L = nullptr;
const char* const ARG_TYPE_NOT_MATCH = "the type of argument is not match";
const char* const ARG_NUM_INVALID = "the number of arguments is invalid";
const char* const STACK_OPS_INPUT_ARG_INVALID = "the input argument passed to the stack ops is invalid";
};
If you are looking for a clean solution you could use a function that does, what the default constructor should do. This way you don't need constructor delegation, which afaik can't be applied conditional and you don't have to mess with placement new.
Minimal example:
class Ctx
{
private:
void DefaultInit()
{
m_L = malloc(100);
std::cout << "set m_L=" << m_L << std::endl;
}
public:
Ctx(RUN_MOD runType)
{
if(runType == MOD_RT)
{
this->DefaultInit();
}
}
Ctx()
{
this->DefaultInit();
}
}
Calling ctor of any class makes an instance of it, in your posted code it is obvious that allocated m_l in Ctx() is not belong to the object constructed by Ctx(RUN_MOD runType)
try below code
void init_m_l()
{
m_L = malloc(100);
std::cout << "set m_L=" << m_L << std::endl;
}
Ctx(RUN_MOD runType)
{
if(runType == MOD_RT)
init_m_l();
}
Ctx()
{
init_m_l();
}
It's a good answer, but the author deleted it.
I posted it here for more people to study.
his code:
if(runType == MOD_RT)
{
Ctx();
}
creates a temporary Ctx() object, and -- that's it. Nothing more, nothing less. That temporary just gets destroyed as soon as that line of code is finished executing.
There are other major issues with the class, such as using malloc, the class leaks memory due to not following the rule of 3, not initializing all the members (which I addressed by setting m_L to nullptr), etc.
I found a solution, here is the code snippet(https://coliru.stacked-crooked.com/a/964309f60f62dbd4, it works, but I am still trying to understand it):
#include<iostream>
class Ctx
{
public:
enum RUN_MOD
{
MOD_RT,
MOD_NRT,
};
Ctx(RUN_MOD runType)
{
if(runType == MOD_RT)
{
new (this)Ctx();
}
}
Ctx()
{
m_L = malloc(100);
std::cout << "set m_L=" << m_L << std::endl;
}
void print()
{
std::cout <<"print() m_L=" << m_L << std::endl;
}
~Ctx()
{
free(m_L);
}
Ctx(const Ctx&) = delete; //to avoid double free
private:
void *m_L;
const char* const ARG_TYPE_NOT_MATCH = "the type of argument is not match";
const char* const ARG_NUM_INVALID = "the number of arguments is invalid";
const char* const STACK_OPS_INPUT_ARG_INVALID = "the input argument passed to the stack ops is invalid";
};
int main()
{
Ctx ctx(Ctx::RUN_MOD::MOD_RT);
ctx.print();
}
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;
}
I'm trying to understand virtual classes in C++. In Wikipedia, I found this example:
#include <iostream>
class Machine {
public:
void run() { }
class Parts {
public:
virtual int get_wheels() = 0;
virtual std::string get_fuel_type() = 0;
};
};
// The inner class "Parts" of the class "Machine" may return the number of wheels the machine has.
class Car: Machine {
public:
void run() {
std::cout << "The car is running." << std::endl;
}
class Parts: Machine::Parts {
public:
int get_wheels() override {
std::cout << "A car has 4 wheels." << std::endl;
return 4;
}
std::string get_fuel_type() override {
std::cout << "A car uses gasoline for fuel." << std::endl;
return "gasoline";
}
};
};
I can get the number of wheels of a car with:
Car::Parts c_p;
c_p.get_wheels();
Is there any other (simple) way? Is there any way instantiating only Car car ?
Update:
I understand the concerns, but I find it useful as a nested interface (with minimal changes):
#include <iostream>
#include <memory>
class Machine {
public:
virtual void run() = 0;
class Parts {
public:
virtual int get_wheels() = 0;
virtual std::string get_fuel_type() = 0;
};
};
class Car: public Machine {
public:
void run() {
std::cout << "The car is running." << std::endl;
}
class Parts: public Machine::Parts {
public:
int get_wheels() override {
std::cout << "A car has 4 wheels." << std::endl;
return 4;
}
std::string get_fuel_type() override {
std::cout << "A car uses gasoline for fuel." << std::endl;
return "gasoline";
}
};
};
int main () {
std::shared_ptr<Machine> X = std::make_shared<Car>();
(*X).run();
std::shared_ptr<Machine::Parts> Y = std::make_shared<Car::Parts>();
(*Y).get_wheels();
return 0;
}
I don't find any other code with this functionality. The only thing I miss is the possibility to access get_wheels directly from X. For instance, let's consider that I have a Machine in my program. The kind of machine I have will be specified dynamically. I want to know the number of wheels of this machine, but the method get_wheels must be inside a nested class Parts. The closer to solve this problem that I've got is with the code above, which gives me Machine and Machine::Parts as interfaces.
A simple solution would be to have a member part of you car:
struct Car : Machine {
struct Parts : Machine::Parts {
int get_wheels() override {
std::cout << "A car has 4 wheels." << std::endl;
return 4;
}
std::string get_fuel_type() override {
std::cout << "A car uses gasoline for fuel." << std::endl;
return "gasoline";
}
} parts; // <---
// or declare it as a separated member:
// Parts parts;
};
That way, you can call member functions like this:
Car car;
std::cout << car.parts.get_weels();
No. As it stands, a Car instance does not have any Car::Parts instances, nor any method that returns one.
The text around the example seems to be assuming that there is an instance of Machine::Parts associated with Machine somehow, which magically becomes a Car::Parts in Car. This may be the case in some other language, but it is not the case in C++.
A much more idomatic design would be to have a traits class template that Machine subclasses specialise.
template <typename Machine>
struct MachineParts;
template <>
struct MachineParts<Car> {
static int get_wheels() {
std::cout << "A car has 4 wheels." << std::endl;
return 4;
}
static std::string get_fuel_type() {
std::cout << "A car uses gasoline for fuel." << std::endl;
return "gasoline";
}
};
template <>
struct MachineParts<Bicycle> {
static int get_wheels() {
std::cout << "A bike has 2 wheels." << std::endl;
return 2;
}
static std::string get_fuel_type() {
std::cout << "A bike uses muscles for fuel." << std::endl;
return "muscles";
}
};
It's a long time ago since my last c++ project and now I'm stuck in a very simple problem. I create two objects and want to modify only one of them. Now I don't understand why the other object is also modified...
MainClass:
#include "testobject.h"
#include <iostream>
int main() {
TestObject o1;
TestObject o2;
std::cout << "object1 before: " << o1.getI() << std::endl;
std::cout << "object2 before: " << o2.getI() << std::endl;
o1.setI(2);
std::cout << "object1 after: " << o1.getI() << std::endl;
std::cout << "object2 after: " << o2.getI() << std::endl;
}
TestObjectClass:
#include "testobject.h"
int i;
int TestObject::getI() {
return i;
}
void TestObject::setI(int j) {
i = j;
}
The output is:
object1 before: 0
object2 before: 0
object1 after: 2
object2 after: 2
Why is i in object2 also set to 2?
The both objects refer to the common variable
int i;
declared in the global namespace. So once the variable is changed the class method
int TestObject::getI() {
return i;
}
will return the same value of the variable i for both objects.
Make the variable a data member of the class.
For example
class TestObject
{
//...
private:
int i;
};
Pay attention to that the member function getI should be declared with the qualifier const because it does not change the object itself
class TestObject
{
public:
int getI() const {
return i;
}
//...
};