I have following classes: Container, Element and then couple of classes that inherit from Element, eg. Button, Input, etc ...
I have a problem when adding the elements to Container array, my main() looks like this:
Container c;
c.Add( Button(...) );
c.Add( Input(...) );
where "..." are some constructor parameters.
In the container class I have a array of pointers to store all elements that belong to that container:
Element ** elements;
But the problem I'm having is how to implement the Add method, I was hoping something like this would work:
void Add(const CControl & newElement){
elements[elemCnt++] = &newElement;
}
(the elements array is allocated: elements = new Element * [100];)
However I am getting this compilation error:
main.cpp: In member function ‘Container& Container::Add(const Element&)’:
main.cpp:138:23: error: invalid conversion from ‘const Element*’ to ‘Element*’
When I remove the const qualifier, I get a compilation error saying there is no suitable candidate.
The thing is, I am new to polymorphism and inheritance in C++, so I might be going wrong way about this. What would be the best approach on this?
PS: The main method must look the same, also don't suggest any vector or STL stuff.
Add should take a pointer:
void Add(CControl * newElement){
elements[elemCnt++] = newElement;
}
then you can call it like this
c.Add( new Button(...) );
c.Add( new Input(...) );
If you really cannot change the calling code, you need to somehow create a copy of the temporary.
E.g. by implementing a virtual Clone method in CControl, Input, Button an call it in Add.
void Add(const CControl & newElement){
elements[elemCnt++] = newElement.Clone();
}
It is impossible to fix this code without changing main, because you attempt to store a reference to a temporary. This is undoable no matter what you do.
Related
I am having vector, that stores classes of type Sensor, which each have a member function refresh(). This vector is member of my class LogManager.
class Sensor
{
public:
void refresh();
}
class LogManager
{
private:
std::vector<Sensor*> sensors;
void refresh_sensors()
{
// TODO: use foreach
for (uint i=0; i<sensors.size(); i++)
{
sensors[i]->refresh();
}
for_each(sensors.begin(), sensors.end(), [sensors]( void* ) void* -> {refresh();} );
}
}
What I want to do is to change the for loop into the std::for_each() implementation. What you see above is my first try.
How can I access the member function Sensor::refresh() with the for_each() function?
Using a standard for loop like also above, I'd just use the -> operator.
Stretch goal is also to replace the std::vector<Sensor*> sensors; with a pointer: std::vector<Sensor*>* sensors; so that I do not have to work with copies. How would the implementation look in this case?
Hmm.
for_each(sensors.begin(), sensors.end(), []( Sensor * sensor ) void -> { sensor->refresh(); } );
I didn't try compiling it, so there might be a syntax problem. Things I changed:
You're not using the [sensors] section, so I emptied that.
If you're using void *, you're almost certainly doing something very un-C++-like. I changed it to the proper type.
You're not returning any value, so I changed the void * to void.
I don't actually use for_each. I personally think this code is far cleaner:
for (Sensor * sensor: sensors) {
sensor->refresh();
}
I think that's SIGNIFICANTLY easier to read. So doing it using for_each is a good practice problem, but I wouldn't have written it that way. Which also means I might have gotten the code slightly wrong.
You don't need to capture anything in the lambda in for_each. Instead, each pointer in the vector should be passed as an argument:
std::for_each(sensors.begin(), sensors.end(),
[](Sensor* s) { s->refresh();});
You don't need to (and shouldn't) make the vector a pointer, unless you want to pass it around without making copies. Since it's a private data member, that's probably not a good idea, and you can use references to do that anyway.
I have 2 issues in a template class I'm building. I've included example code below. First question is whether I can coerce the auto type deducted for a templated class. i.e.:
auto p = myvar;
where myvar is T<...>, could I force auto to detect Q<...>? This is simplified. Read on for a more clear explanation.
Edited for clarity: Let me explain what I'm doing. And I'd also like to indicate that this style code is working on a large-scale project perfectly well. I am trying to add some features and functions and in addition to smooth out some of the more awkward behaviors.
The code uses templates to perform work on n-dimensional arrays. The template has a top-level class, and a storage class underneath. Passing the storage class into the top level class allows for a top level class which inherits the storage class. So I start with NDimVar, and I have NDimStor. I end up with
NDimVar<NDimStor>
The class contains NO DATA except for the buffer of data:
class NDimStor<size_t... dimensions> {
int buffer[Size<dimensions...>()]
}
This makes the address of the class == the address of the buffer. This is key to the whole implementation. Is this an incorrect assumption? (I can see this works on my system without any issues, but perhaps this isn't always the case.)
When I create NDimVar<NDimStor<10,10>> I end up with a 10x10 array.
I have functions for getting pieces of the array, for example:
NDimVar<NDimStor<dimensions...>>::RemoveDim & get(int index);
This creates a new 1d array of 10 elements out of the 2d 10x10 array:
NDimVar<NdimStor<10>>
In order to return this as a reference, I use a reinterpret_cast at the location of the data I want. So in this example, get(3) would perform:
return reinterpret_cast<NDimVar≤NDimStor<dimensions...>>::RemoveDim&>(buffer[index * DimensionSumBelow<0>()]);
DimensionSumBelow<0> returns the sum of elements at dimensions 1+, i.e. 10. So &buffer[30] is the address of the referenced 1d NDimVar.
All of this works very well.
The only issue I have is that I would like to add on overlays. For example, be able to return a reference to a new class:
NDimVar<NDimPermute<NDimStor<10,10>,1,0>>
that points to the same original location along with a permutation behavior (swapping dimensions). This also works well. But I would like for:
auto p = myvar.Permute<1,0>()
to create a new copy of myvar with permuted data. This would work if I said:
NDimVar<NDimStor<10,10>> p = myvar.Permute<1,0>().
I feel that there is some auto type deduction stuff I could do in order to coerce the auto type returned, but I'm not sure. I haven't been able to figure it out.
Thanks again,
Nachum
What I want is:
1. Create temporary overlay classes on my storage, e.g. A_top<A_storage> can return a type called A_top<A_overlay<A_storage>> without creating a new object, it just returns a reference to this type. This changes the way the storage is accessed. The problem is upon a call to auto. I don't want this type to be instantiated directly. Can I modify the return to auto to be an original A_top?
#include <iostream>
using namespace std;
class A_storage {
public:
float arr[10];
A_storage () {
}
float & el (int index) {
return arr[index];
}
};
template <typename T> class A_overlay : T {
private:
A_overlay () {
cout << "A_overlay ()" << endl;
}
A_overlay (const A_overlay &) {
cout << "A_overlay (&)" << endl;
}
public:
using T::arr;
float & el (int index) {
return arr[10 - index];
}
};
template <typename T> class A_top;
template <typename T> class A_top : public T {
public:
A_top () {
}
A_top<A_overlay<A_storage>> & get () {
return reinterpret_cast<A_top<A_overlay<A_storage>>&>(*this);
}
};
using A = A_top<A_storage>;
int main (void) {
A a;
auto c = a.get(); // illegal - can i auto type deduce to A_top<A_storage>?
return 0;
}
If a function accepts (A_top<A_storage> &) as a parameter, how can I create a conversion function that can cast A_top<A_overlay<A_storage>>& to A_top<A_storage>& ?
Thanks,
Nachum
First, your design doesn't look right to me, and I'm not sure if the behaviour is actually well-defined or not. (Probably not.)
In any case, the problem is not with auto. The error is caused by the fact that the copy constructor of A_overlay is private, while you need it to copy A_top<A_overlay<A_storage>> returned by a.get() to auto c.
(Note that the auto in this case obviously gets deduced to A_top<A_overlay<A_storage>>, I assume you made a typo when said that it's A_top<A_storage>.)
Also note that A_storage in A_top::get() should be replaced with T, even if it doesn't change anything in your snippet because you only have T == A_storage.
If a function accepts (A_top &) as a parameter, how can I create a conversion function that can cast A_top> to A_top& ?
Ehm, isn't it just this:
return reinterpret_cast<A_top<A_storage>&>(obj);
reinterpret_cast should almost never be used. It essentially remove any compiler validation that the types are related. And doing unrelated cast is essentially undefined behavior as it essentially assume that derived classes are always at offset 0...
It does not make any sense to write such code. It is not maintainable and hard to understand what you are trying to achieve. It look like you want to pretend that your A_top<A_storage> object is a A_top<A_overlay<A_storage>> object instead. If this is what you want to do, then declare A alias as that type.
In your code, it look like you want to invert the indexing so that item at position 10 is returned when you ask item at position 0 and vice versa. Do you really think, that it is obvious from your obfuscated code? Never write such bad code.
Something like
class A_overlay {
public:
float & el (int index) { return arr[10 - index]; }
private:
A_storage arr;
};
would make much more sense than your current code.
No cast needed.
Easy to understand.
Well defined behavior.
You might keep your job.
And obviously, you would update the following line as appropriate:
using A = A_top<A_storage>;
Also, if A_top has no useful purpose, then why not using A_overlay directly? And why are you using template if A_storage is not a template? Do you really want to reuse such mess elsewhere in your code base.
Obviously, your code inheritance does not respect IS-A relationship if your write such code. So it is clearly a bad design!
I have 3 classes. DrawGameComp' and 'GameComp' where 'GameComp' is the base class of 'DrawGameComp'. I have an array of pointers in Game class which is the controlling class. '
GameComp * components[]; From the main I have to create a dynamic instance of Game and store add new objects of GameComp and DrawGameComp to the array of pointers of type GameComp.
Game Game1(2);
Game1.Add(new GameComponent);
Game1.Add(new DrawableGameComponent);
I'v done this part in the main. Because from the main I have to invoke Add passing object as the parameter. When i store these objects I also want assign an id of 1 to the first object and an id of 2 to the second object. How can i include that too.
The Add() function of my Game class is as follows
void Game::Add(GameComponent*)
{
components[0]=GameComp;
componentCount++;
}
but it give me error. I have tried so hard. But I couldn't. Also how do I invoke the Display() member function of these objects in the Array? is it this way?
components[0]->Display();
The Add method should look like:
void Game::Add(GameComponent* comp)
{
components[componentCount++] = comp;
}
Make sure you zero out componentCount in the constructor.
Using the array:
components[i]->DoSomething();
1) You probably meant to write the following:
void Game::Add(GameComponent* comp)
{
components[componentCount++] = comp;
}
2) components[0]->Display() will work, if display is a member function of GameComponent class.
Suppose I have the following class:
class DX11ConstantBuffer
{
public:
ID3D11Buffer *pData;
};
I receive an array of this class in a function:
DX11ConstantBuffer **pp
My wrapper (DX11ConstantBuffer) contains a pointer to ID3D11Buffer. The following function:
pDevcon->VSSetConstantBuffers
requires a pointer to an array of ID3D11Buffers,
ID3D11Buffer *const *ppConstantBuffers
As the function receives a pointer to an array of my own wrapper, what would be the fastest way to create an array of ID3D11Buffers from it? To make it clearer:
void ...(DX11ConstantBuffer **pp, ....)
{
ID3D11Buffer** _pp = GetAllID3D11BufferElementsFrom(pp);
pDevcon->VSSetConstantBuffers(..., _pp, ...);
}
The function is meant to be called several times each frame.
The fastest way is proactively, i.e. to have maintained a contiguous array of ID3D11Buff* before needing to call VSSetConstantBuffers, for which you'd want a std::vector<ID3D11Buff*>. You could update the vector whenever DX11ConstantBuffer::pData is set, or DX11ConstantBuffer's destructor runs, and if you want better assurances around that you can make pData private and have accessor functions which can reliably intercept changes.
If you don't do it proactively, then with your current objects you've no choice but to iterate over the DX11ConstantBuffers and copy out the ID3D11Buf*s to an array/vector one-by-one....
You can make the wrapper inherites from the type it includes.
For a class X and a QSet< X* >, how is it possible to make sure that the QSet doesn't contain duplicate elements?
The unique property in each object of type X is a QString that can be fetched using getName().
I've implemented the qHash(X*) function, the operator==(), operator<() and operator>(), but the QSet still accepts duplicate elements, i.e., those with the same Name.
Could someone help me out in making this work?
Ok. Here's what I'm trying to do.
I have a class Y and a class X, both of which inherit QDialog. A function in class Y ( a slot), is responsible for spawning objects of class X. The dialog for Y is to be made responsible for the X objects spawned. This is why I created a QSet< X* > member in Y.
The problem is that you cannot overload operator== like this:
bool operator==(X*, X*);
This is because at least one of the argument must be of class type.
Since you say you implemented operator==, I suppose you did something like this:
struct X
{
bool operator==(X*) const;
};
This operator will never be called when QSet tries to fiend duplicates because it needs a left argument of type X and a right of type X*
I can see two possible solutions to this problem:
Do not store your items as pointers (ie using QSet<X>). This will allow you to overload the correct operators. This solution, however, is not always feasible.
If you could enforce somehow that there is only one object with a given id, you could just store pointers in you QSet without needing to overload any operators nor the qHash function.
Edit: If your design allows to create multiple X-objects with the same id but you only want one such object to exist at any time, maybe it's best to use a QMap which maps from id to X*. When you create a new object, do something like this:
QString newId = ...;
delete objectsMap[newId];
objectsMap[newId] = new X(newId);
Depending on your exact requirements, you could use a sorted vector together with std::unique (which accepts a custom binary predicate for comparison).
Could you use QMap instead? Your dialog would have member variable QMap<QString, X*> items. Then the checking and creating new X's would be like:
QString name = "foo";
if (!items.contains(name))
{
items[name] = new X(name);
}
else
{
// "foo" already exists
}
Maybe this is not as elegant solution as using QSet might be, but I think this is shorter and easier to understand.
I get exactly the same problem. In the end I get here. My solution is very simple.
If class QSet can't do what I want, why don't use it object in my class with added code to every function I need. Here is my solution:
Declaration of Set class:
#pragma once
#include<Plant.h>
#include<qset.h>
class Set
{
public:
Set(void);
~Set(void);
bool contains(Plant *plant);
QSet<Plant*>::iterator insert(Plant *plant);
QSet<Plant*>::iterator erase(Plant *plant);
private:
QSet<Plant*> plants;
};
Definition of Set class
#include "Set.h"
Set::Set(void){
plants = QSet<Plant*>();
}
Set::~Set(void){
}
bool Set::contains(Plant *plant){
for(int i=0;i<plants.size();++i){
if(plants.values().at(i)->compare(plant))
return true;
}
return false;
}
QSet<Plant*>::iterator Set::insert(Plant *plant){
if(!contains(plant))
return plants.insert(plant);
}
QSet<Plant*>::iterator Set::erase(Plant *plant){
QSet<Plant*>::iterator it;
for(it = plants.begin();it!=plants.end();++it){
if((*it)->compare(plant)){
return plants.erase(it);
}
}
return it;
It worked for me very well.