I have a base class and a class derived from it. In the example below, Frame_Pic is a derived class of Base_Pic, the details of which I have not included. Frame_Pic has members, vertical,horizontal, and corners which is not in the base class. Picture is an interface class and basically holds a pointer to Base_Pic.
When I try to assign new values to these in the reframe function below, I get an error stating that Base_Pic has no such data members.
The action, pic.p->vertical, will think I am accessing the base class. If I put these data members in the base class, the rest of my functions are written in a way that it will not accommodate this addition. How can I assign to these data members?
Picture frame(const Picture& pic, char v, char c, char h)
{
Frame_Pic* temp = new Frame_Pic(pic.p);
temp->vertical = v;
temp->horizontal = h;
temp->corners = c;
Picture temp2(temp);
return temp2;
}
void reframe(Picture& pic, char v, char c, char h)
{
pic.p->vertical = v;
pic.p->horizontal = h;
pic.p->corners = c;
}
Sounds like you want to set items of a derived class while feeding a function a pointer to the base type. The way to do this is to create a virtual function in the base class and implement it in the derived class.
for instance...
virtual void BaseClass::SetupSomeStuff(...) {
}
void DerivedClass::SetupSomeStuff(...) {
your assignments here
}
Instead of accessing them directly, use your Picture interface to declare set and get methods (assuming both are needed) for those members, and implement them in the derived class.
Direct access to member variables does not behave polymorphically, hence your error.
You should rethink the way you wrote the functions and how the classes interact in general.
Reframe might be a function member of Frame_Pic but its functionality has nothing to do with any instance of the class Frame_Pic. In fact, since all you can know for sure is that Picture holds a pointer to a Base_pic, it might as well hold a pointer to an instance of a different class that derives Base_pic that does not define members named vertical, horizontal or corners.
You should instead create a new Frame_pic instance like you did in the first function and set the pointer in Picture to that new instance. You might also want to mark these two functions as static if they are not, already.
Related
I have a "chain" class, meaning a class that manages a sequence of objects with a common base class.
This chain class should execute the member function processSample(a, b) for any child class (of baseClass) I add.
I want to be able to code more child classes (with a processSample(a, b) function) later on, and add them to the chain without having to edit the chain class.
I could use a template in the add function but this doesn't solve the problem that there is no data structure for different datatypes (of different sizes) right?
Functions of the children called in the Chain class should all be overridden virtuals from the base class.
class baseClass
{
public:
virtual float processSample(int a, float b)
{
}
};
class Chain
{
const int maxChilds = 20;
?sometype? allChilds[maxChilds];
public:
float processSample(int c, float d)
{
for (int i = 0; i < maxChilds; i++)
{
input = allChilds[i].processSample(a, b);
}
return input;
}
void addChild(?sometype? newChild)
{
allChilds.push_back(newChild)
}
}
You would want to use pointers or references, to avoid initialization or copy operations as part of creating the class.
For example
class Chain
{
const int maxChilds = 20;
baseClass allChilds[maxChilds];
Will create, and initialize an array of 20 baseClass instances. Whereas this:
class Chain
{
const int maxChilds = 20;
baseClass* allChilds[maxChilds];
Will create an array of pointers to baseClass, which can also point to instances of any child classes. Do consider which class will be responsible for allocation and de-allocation of the memory for these instances (this can either be within this class, or the caller / user of this class - which one is ideal will depend on the rest of your design). You could also consider using a smart pointer instead and let that manage the memory for you: https://en.cppreference.com/book/intro/smart_pointers
Similarly:
void addChild(baseClass newChild)
Will use pass-by-value to pass in a copy of newChild (using the copy constructor of baseClass), any instances of child classes will either fail or be converted to an instance of baseClass. Whereas if you instead go with:
void addChild(baseClass& newChild)
It will use pass-by-reference instead, and the function will receive a reference to the original object.
The nice effect of virtual is, that you "call a function of the base class", but the function of the derived class will be executed.
So ?sometype? allChilds[maxChilds]; is baseClass allChilds[maxChilds];. The chain should be the holder of the objects, so addChild(...) should not accept an instance of the child-class. It should create the instance and use (if necessary) std::move to add it to the array.
Remark: It will be easier for you using
std::vector<baseClass>allChilds;
allChilds.reserve(maxChilds); //reserves the memory but you can still use push back
I'm trying to figure my head around polymorphism and pointers and am following some wonderful videos explaining it (hyperlink if you really care)
He declares class A and class B which inherits from A.
But to instantiate an object of B he does so like this:
A* b = new B;
and it works fine (and he continues to use that method when creating more complex classes, a vector array of base type Shape that contains child classes Square, Circle etc. i.e.
std::vector<Shape*> shapes;
shapes.push_back(new Circle.........
shapes.push_back(new Rectangle.......
It is possible, but is it totally fine (and even recommended) to declare a pointer to an object of a base class, but then instantiate it by pointing to its child class??
I guess I just answered my own question, that the benefit comes from being able to manage collections of different objects by referring to them by their parent class? Is that correct?
Thank you!
but is it totally fine (and even recommended) to declare a pointer to an object of a base class, but then instantiate it by pointing to its child class?
When you use
A* ptr = new B();
instead of
B* ptr = new B();
you are losing just a small amount of information. You cannot use any member functions that are defined in B but not in A. Please note that it is perfectly fine to use virtual member functions declared in A but implemented in B.
If that small amount of loss is OK in your use case, then there is no harm in using A* ptr =. If you would like to be able to preserve the B-ness of the pointer so you can use it to access members that are specific to B, it will be necessary to use B* ptr =.
There is a guiding principles about using pointer/reference types:
When defining a function interface, use a pointer/referene type that is as higher up in the class hierarchy as you can get away with to implement the function.
Given
struct Shape { ... };
struct Circle : Shape { ... };
don't use Circle in the interface of a function if everything you need in the function can be obtained from a Shape.
When you add the next sub-class of Shape,
struct Rectangle : Shape { ... };
that function can be used with a Rectangle too without any change.
When defining a pointer/reference, use a type that preserves as much information as possible.
If there is a function
Circle* someFunction();
then, use
Circle* circlePtr = someFunction();
instead of
Shape* shapePtr = someFunction();
You can use circlePtr for wherever you need a Shape* but you won't be able to use shapePtr wherever you need a Circle*.
You partly answered your question, but there can also be other reasons.
Polymorphism is so you can keep some things abstract. Imagine, for instance, code like this:
Person *actor;
if (occupation == 'nerd') {
actor = new NerdPerson();
}
else if (occupation == 'mortician') {
actor = new MorticianPerson();
}
...
actor->printOccupation();
Clearly that's a made up reason. So it MIGHT be about collections of something, but that's only one reason.
I have this block of code:
struct Road_Primitive {
public:
Road_GPU_Point A;
Road_GPU_Point B;
Road_GPU_Point C;
};
struct Road_Primitive_4P : public Road_Primitive {
Road_GPU_Point D;
};
struct Road_Primitive_3P : public Road_Primitive{
};
And in one of my classes I have a Road_Primitive*, which is initialized with either new Road_Primitive_4P or new Road_Primitive_3P, depending on other factors.
However, this section of code gives me an "class Road_Primitive has no member D":
Road_Primitive* pmtv_Prospect = new Road_Primitive_4P;
pmtv_Prospect->D.X = pch_Rightmost->GPU_Primitive->B.X;
However, if I declare Road_Primitve with protected members, the error turns into something like: "Member B is inaccesible"
Any suggestions?
Well, class Road_Primitive hasn't any member D. Every expression is interpreted in light of the declared types of all its sub-expressions, as evaluated by the compiler. The fact that pmtv_Prospect currently points to a Road_Primitive_4P at some point during the execution doesn't factor in -- if you access that Road_Primitive_4P via a Road_Primitive * then you have access only to those members declared by class Road_Primitive.
If you want to be able to access Road_Primitive_4P.D, then you must do so via a value of (declared) type Road_Primitive_4P. Thus, you could write
Road_Primitive_4P* pmtv_Prospect = new Road_Primitive_4P;
pmtv_Prospect->D.X = pch_Rightmost->GPU_Primitive->B.X;
Of course, in that case you cannot assign pmtv_Prospect to point to a Road_Primitive_3P, but that's really the whole point. If you could make it point to a Road_Primitive_3P, which has no member D, then it would not be safe to access the referent's D.
struct Road_Primitive, does not, in fact, have a member called D. Although you're allocating a Road_Primitive_4P, you're storing it in a pointer to type Road_Primitive, so when you access (pmtv_Prospect) you only have access to the fields in Road_Primitive.
Usually when you store instances of child classes as parent classes, you want polymorphism, and virtual methods, or else some other means of telling which of those child classes the pointer really points to.
In order to use "dynamic_cast" as Gaurav suggested, your structs or classes need to have at least one virtual method. Starting with a destructor is probably a good idea:
struct Road_Primitive {
public:
virtual ~Road_Primitive() {};
// etc.
And one in each child class:
struct Road_Primitive_4P: public Road_Primitive {
public:
virtual ~Road_Primitive_4P() {};
Then if you have a Road_Primitive pointer and want to access members of it that are only accessible in Road_Primitive_4P you can use dynamic_cast:
Road_Primitive_4P* temp = dynamic_cast<Road_Primitive_4P*>(pmtv_Prospect);
if (temp) // then do something with temp->D
dynamic_cast() will return 0 if the object doesn't match the type you're trying to cast to.
Also bear in mind that this style of polymorphism is generally considered bad style because it tends to centralize behaviors that are specific to the different types. Using virtual methods is usually preferable because the behavior specific to each type is stored in the definition of that type.
I'm coming from a C# background and now trying to pick up C++. I'm using an abstract class that has a static member to keep track of the total number of that object type, and a static method to get the count. for example:
class Shape
{
public:
virtual void Draw() = 0;
static int GetShapeCount();
private:
static int mShapeCount;
};
I noticed that derived classes are also able to call the abstract class static method, which I found a little curious/confusing. For instance, someone might get confused if they are able to do something like:
Shape *newShape = new Rectangle();
cout << newShape->GetShapeCount();
Does that mean get rectangle count or shape count? I also noticed that even if you don't explicitly call it a shape you can still access the static method through derived classes:
Rectangle rectClass = Rectangle();
cout << rectClass.GetShapeCount();
So my question is two-fold:
1)Why/How is this possible
2)Is there a way to not allow derived classes to call abstract class static methods?
Edit:
my test that I ran in C# was incorrect, and it shows similar behavior... it just seems odd to me that the static methods would fall through to the derived classes as well. It seems consistent though with other languages, and I suppose I just made a mistake.
No, C++ doesn't have polymorphic static functions, so supposing static getShapeCount() was implemented as return mShapeCount;, it will return the base class value. However this could be easily simulated using CRTP and static polymorphism. Since is not a good practice to call static functions from objects instead of the class itself, this works like a charm.
I also noticed that even if you don't explicitly call it a shape you can still access the static method through derived classes
You have declared getShapeCount() public, isn't? And you (I suppose, again, because you haven't showed us enough code) have used public inheritance.
Shape *newShape = new Rectangle();
cout << newShape->GetShapeCount();
is a way to write cout << Shape::GetShapeCount().
as
Rectangle rectClass = Rectangle();
cout << rectClass.GetShapeCount();
is a way to write cout << Rectangle::GetShapeCount() which turns into Shape::GetShapeCount().
If you want to prohibit Rectangle::GetShapeCount()
you may add a deleted function (C++11):
class Rectangle : public Shape
{
public:
// Previous methods
static int GetShapeCount() = delete; // forbid the usage Rectangle::GetShapeCount()
};
I noticed that derived classes are also able to call the abstract class static method, which I found a little curious/confusing.
This is the same behavior that you have in C#: derived classes have access to all methods of their base class, as long as their visibility (public, protected, internal, etc.) allows for it.
Does that mean get rectangle count or shape count?
It's the shape count, because all derived classes share the same counter.
Is there a way to not allow derived classes to call abstract class static methods?
Yes - you can hide a method from derived classes by making it private.
If you would like to keep separate object counts per derived class, you can make a static map<type_index,int>, and increment the counter of your specific type. However, you wold need to give your static method an access to the type of the caller.
I have a c++ class derived from a base class in a framework.
The derived class doesn't have any data members because I need it to be freely convertible into a base class and back - the framework is responsible for loading and saving the objects and I can't change it. My derived class just has functions for accessing the data.
But there are a couple of places where I need to store some temporary local variables to speed up access to data in the base class.
mydata* MyClass::getData() {
if ( !m_mydata ) { // set to NULL in the constructor
m_mydata = some_long_and complex_operation_to_get_the_data_in_the_base()
}
return m_mydata;
}
The problem is if I just access the object by casting the base class pointer returned from the framework to MyClass* the ctor for MyClass is never called and m_mydata is junk.
Is there a way of only initializing the m_mydata pointer once?
It doesn't have members and you must maintain bit-for-bit memory layout compatibility… except it does and C++ doesn't have a concept of freely-convertible.
If the existing framework allocates the base objects, you really can't derive from it. In that case, I can think of two options:
Define your own class Cached which links to Base by reference. Make the reference public and/or duplicate Base's interface without inheritance.
Use a hash table, unordered_map< Base *, mydata > mydata_cache;. This seems most appropriate to me. Use free functions to look up cache data before delegating to the Base *.
You could initialize your private variables in a separate initialization member function, so something like this:
class MyClass {
public:
init() {
if (!m_mydata) {
m_mydata = f();
}
}
};
framework_class_t *fclass = framework.classfactory.makeclass();
MyClass *myclass = (MyClass*)fclass;
myclass->init();
char *mydata = myclass->getData();
It's hard to say if this is a good idea or not without knowing what framework you're using, or seeing your code. This is just the first thing that came to mind after reading your description.
You could create a wrapper for the factory of the framework. The wrapper would have the same interface, delegate calls to the framework but it could initialize the created base class instance before returning it. Of course, this requires you to change your code to use the wrapper everywhere, but if it is possible, after that you can be sure that the initialization happens properly.
A variation on this: use RAiI by wrapping the base class instances into a custom autopointer which could do the initialization in its constructor. Again, if you manage to change the code everywhere to use the new wrapper type instead of the derived class directly, you are safe.