I got an elegant answer yesterday for my question regarding polymorphic object members.
But now I am facing the problem that the variable isn't really behaving the way I expected it to. The following code is being used:
#include <iostream>
#include <math.h>
using std::cin;
using std::cout;
using std::endl;
class Com
{
public:
virtual void setReady()
{
cout << "Com" << endl;
}
};
class DerivedCom : public Com
{
public:
void setReady()
{
cout << "DCom" << endl;
}
void somethingElse()
{
cout << "else" << endl;
}
};
class BaseClass
{
public:
Com* com;
public:
BaseClass(Com* c = new Com) : com(c)
{
}
virtual void setReady()
{
com->setReady();
}
};
class DerivedClass : public BaseClass
{
// the call to somethingElse() won't compile if I leave out this declaration
protected:
DerivedCom* com;
public:
DerivedClass() : BaseClass(new DerivedCom)
{
}
void setReady()
{
// This line causes a segfault if I put in the declaration earlier
this->com->setReady();
// This line won't compile if I leave out the declaration earlier
this->com->somethingElse();
}
};
int main()
{
DerivedClass* inst = new DerivedClass();
inst->setReady();
return 0;
}
The problem is, that DerivedClass::com is in fact of type DerivedCom but I can't access any DerivedCom-specific methods as the compiler won't find them. If I put in an extra re-declaration DerivedCom* com, the compiler will find the methods but I get segmentation faults.
Remove that extra declaration.
If you are sure that a Com* is a DerivedCom* then you can static_cast it.
static_cast<DerivedCom*>(this->com)->somethingElse();
This will likely crash it you're wrong however. So if you are not sure then you can dynamic_cast it
DerivedCom* dcom = dynamic_cast<DerivedCom*>(this->com);
if (dcom)
dcom->somethingElse();
dynamic_cast will return NULL if the object isn't of the type you asked for.
The reason for the segmentation faults is that you arent declaring the variable again with a different type, you are actually defining a new pointer in the derived class, one that is never initialized. Thus this->com->... will access the derived class com and crash since it is an uninitialized pointer.
What you are trying to do though, is to change the type of the member pointer. You could do that by making the type of the member pointer as a template variable, as follows
template <class ComType>
class BaseClassTemplate
{
ComType* com;
...;
};
typedef BaseClassTemplate<Com> BaseClass;
class DerivedClass : public BaseClassTemplate<DerivedCom>
{
...;
};
However this makes the base class a template, so to get it as you want it, you need to make an instantiation of BaseClass<Com> to get your version of base class. You can either make it a derived class or just a typedef as i have shown.
Related
Hello everyone and thanks for reading,
I'm new to working with classes and I've ran into an issues with making array's of objects,
I have a base class, and an array of the same type, I'd like to know if it's a possibility to
make subclasses of the base class type and put them into an array and call methods that're not
in the base class, sorry if this is a bad question and my apologies if my wording is off,
#include <iostream>
int main()
{
BaseClass* ObjectList[10];
ObjectList[0] = new SubClass;
ObjectList[0]->Load(10);
ObjectList[0]->OtherFunction(); // How Can I Do This?
return 0;
}
class BaseClass
{
public:
virtual void Load(int Num) = 0;
};
class SubClass : public BaseClass
{
void Load(int Num) override
{
std::cout << Num << std::flush;
}
void OtherFunction()
{
// Do Something
}
};
Thanks
Edit -
My intent is to have a simple base class with dozens and dozens of subclasses with different methods, and have an array of the base class,
You can always have more than one pointer (or reference) to the same object.
int main()
{
BaseClass* ObjectList[10];
SubClass TheSubclass;
ObjectList[0] = &TheSubclass;
ObjectList[0]->Load(10); // presumably in a loop
TheSubclass.OtherFunction();
return 0;
}
You will have to downcast your pointer to the real class (or at least a class having the method). You can use either a static_cast if you do not need any control, or a dynamic_cast if you want a run-time validation of the cast:
...
SubClass *psc = dynamic_cast<SubClass *>(ObjectList[0]);
if (psc != nullptr) { // an invalid cast would set it to NULL
psc->OtherFunction();
}
else {
// process the error
}
I have following classes:
class ATemperatureDevice{};
class AHumidityDevice{};
class BluetoothLeDevice{};
class Sensor1 : BluetoothLeDevice, ATemperatureDevice, AHumidityDevice {};
class Sensor2 : BluetoothLeDevice, AHumidityDevice {};
I have a vector<BluetoothLeDevice*>, where all devices are stored.
The Classes ATemperatureDevice, AHumidityDevice and BluetoothLeDevice have virtual functions.
When I pick one, I have a BluetoothLeDevice. Now I want to check if it derives from ATemperatureDevice and/or AHumidityDevice.
I tried dynamic_cast, when its not castable, I should get null but, it says "'dynamic_cast' not permitted with -fno-rtti" although they have virtual functions.
What's the best way to check and cast?
As people already commented, storing polymorphic objects T inside a std::vector<T> will cause object slicing. Your code makes sense in C#, but in C++ people tend to use composition over inheritance whenever possible to avoid such issues. In your case this could look like: https://godbolt.org/z/xna1vjnWh
If dynamic_cast is not permitted, then store tag to identify derived class.
// Test sample
#include <iostream>
using namespace std;
class BluetoothLeDevice
{
public:
enum class DerivedClassMetaInfo
{
Sensor1Tag,
Sensor2Tag
};
virtual ~BluetoothLeDevice()
{
}
virtual DerivedClassMetaInfo tag(void) const = 0;
template <typename TargetType>
TargetType& to()
{
if (TargetType::static_tag != tag())
throw "Convertion failed";
return static_cast<TargetType&>(*this);
}
};
class Sensor1 : public BluetoothLeDevice
{
public:
static const BluetoothLeDevice::DerivedClassMetaInfo static_tag = BluetoothLeDevice::DerivedClassMetaInfo::Sensor1Tag;
void show()
{
cout << "Sensor1 message" << endl;
}
virtual DerivedClassMetaInfo tag(void) const override
{
return static_tag;
}
};
int main()
{
BluetoothLeDevice* temp = new Sensor1();
Sensor1& sens = temp->to<Sensor1>();
sens.show();
delete temp;
return 0;
}
Note: use this code with cautions, because it does not handle tricky inheritance trees. However you can easy (I guess) improve it
class MainClass
{
string _ClassName;
public:
string MainClass(string _C)
{
_ClassName = _C;
}
SubClass s1;
};
class SubClass : public MainClass
{
public:
string Method_1()
{
return a;
}
string Method_2()
{
return a;
}
};
Why is SubClass s1 not working can someone tell me please what am i missing I'm new to OOP.
I want to instantiate SubClass object inside MainClass but it doesn't seems to work.
basically, my aim is to access SubClass functions when MainClass object is instantiated in Main method something like this:
int Main()
{
MainClass M1("test");
M1.s1.Method_1(); <--------- this
}
The first problem is, that the MainClass does not know a thing about SubClass when you're trying to instantiate the object.
You need to use a forward declaration and a pointer to make it work.
Header file:
class SubClass; //Forward declaration, allows pointer.
class MainClass
{
string _ClassName;
public:
MainClass(string _C); //No return type on constructor
~MainClass();
SubClass *s1; //Size: 4 Bytes on 32bit system
protected:
MainClass();
};
class SubClass : public MainClass
{
public:
string Method_1();
string Method_2();
};
CPP file:
#include "headerFile.h"
MainClass::MainClass(string _C) :
_ClassName(_C),
s1(new SubClass) //Class definition is now known.
{
}
MainClass::MainClass() : s1(nullptr) //Nullptr -> No new object, no infinite recursion.
{
}
MainClass::~MainClass()
{
delete s1; //Do not forget to clean up your pointer.
}
string SubClass::Method_1()
{
return "a";
}
string SubClass::Method_2()
{
return "a";
}
Call:
int main()
{
MainClass M1("test");
M1.s1->Method_1(); //-> to dereference the pointer.
}
The second problem, as Richard Critten has pointed out, is an infinite recursion, which will cause your program to crash very quickly.
Each time you instantiate a SubClass, you also create a subclass, which creates yet another MainClass etc.
To circumvent this, you'll need a protected constructor, which does NOT create the subclass member.
The third problem:
You are returning a in your methods, which suggests a variable.
If you meant to return 'a', you need to put them into quotation marks.
Finally, in order to get it to compile, you'll need to write Main with a small m (int main()), otherwise the linker will complain.
However, as Mr. 'Not a number' correctly stated, the above edits only make your code compile.
What you likely are actually after however would be using virtual functions, which can be overridden by sub classes to specialize the behavior.
An example code using actual inheritance:
Header file:
class MainClass
{
string _ClassName;
public:
MainClass(string _C); //No return type on constructor
virtual ~MainClass(); //All base classes that have at least one virtual method should also have a virtual destructor, even if it is empty.
virtual void doSomething();
};
class SubClass : public MainClass
{
public:
SubClass(string className);
void doSomething();
};
CPP file:
#include "headerFile.h"
#include <stdio.h>
MainClass::MainClass(string _C) : _ClassName(_C)
{
}
MainClass::~MainClass()
{}
void MainClass::doSomething()
{
printf("Called from MainClass\n");
}
SubClass::SubClass(string className) : MainClass(className)
{
}
void SubClass::doSomething()
{
printf("Called from SubClass\n");
}
Call:
int main()
{
MainClass M1("test");
SubClass sub("SubClass");
MainClass *pointer = ⊂
M1.doSomething(); //Outputs 'Called from MainClass'.
sub.doSomething(); //Outputs 'Called from SubClass'.
pointer->doSomething(); //Also outputs 'Called from SubClass', since it points to sub and because sub overrides the behaviour from MainClass.
}
To call the parent method from the child method, you need to invoke the method from within the override with the parent class.
Example (in SubClass::doSomething): MainClass::doSomething().
I've written code in cpp to test my understanding of dynamic dispatching. I think that in my program the output should be "I'm in NT". My reasoning is:
tMethod is defined to be virtual, so dynamic binding will be used
at run time the class-type of test is NT, so call to test->tMethod(ont) should look for the implementation inside NT
actual parameter ont is of type NT, so exact match is found to be NT's impementation of tMethod
However, the output of this program is "I'm in T".
What is wrong in my reasoning?
#include <iostream>
using namespace std;
class T {
public:
virtual void tMethod(T){
cout<<"I'm in T"<<endl;
}
};
class NT: public T{
public:
void tMethod(NT){
cout<<"I'm in NT"<<endl;
}
};
int main()
{
NT ont;
T* test=new NT();
test->tMethod(ont);
return 0;
}
This method:
void tMethod(NT){
does not override this one:
virtual void tMethod(T){
you have changed parameter type from NT to T
You can add override to turn this bug it into error:
void tMethod(NT) override {
will output:
main.cpp:16:18: error: 'void NT::tMethod(NT)' marked 'override', but does not override
void tMethod(NT) override {
[edit]
Your actual question is why C++ does not allow to overload functions across class inheritence, specifically to be able to access derived class functions using base class pointer. The reason is that language does not support this functionality. You can find similar question in Bjarne Stroustrup FAQ: Why doesn't overloading work for derived classes?
NT::tMethod() takes different parameter type to N::tMethod() so it doesn't override. Use the override keyword to protect against this:
#include <iostream>
using namespace std;
class T
{
public:
virtual void tMethod(T) {
cout << "I'm in T" << endl;
}
};
class NT: public T
{
public:
void tMethod(NT) override { // use override keyword here
cout << "I'm in NT" << endl;
}
};
int main()
{
NT ont;
T* test = new NT();
test->tMethod(ont);
return 0;
}
Now you should get a compile error because you marked MT::tMethod() as override but it doesn't because it takes a different parameter type.
You'd better use pointer or reference to base class as an argument in virtual method. If you need to work with a derived class in the overriden method then you can use dynamic_cast.
class T {
public:
virtual void tMethod(T*){
cout<<"I'm in T"<<endl;
}
};
class NT: public T{
public:
virtual void tMethod(T* t) override {
NT* nt=dynamic_cast<NT*>(t);
if (nt)
{
cout<<"I'm in NT as NT"<<endl;
}
}
};
int main()
{
NT ont;
T* test=new NT();
test->tMethod(&ont);
return 0;
}
I'd like to add a shared_ptr<derived> to a map with shared_ptr<base> values (as below http://ideone.com/hd68yc) but it fails (we reach EXIT_FAILURE):
#include <iostream>
#include <map>
#include <memory>
using namespace std;
class base{
public:
base(const int& s = 1):setting{s}{};
int setting;
};
class derived : public base{
public:
derived(const int& s):setting{s}{};
int setting;
};
int main() {
map<string,shared_ptr<base>> m_s;
m_s.insert(make_pair("Name",make_shared<derived>(4)));
// None of these worked either...
//m_s.emplace("Name",make_shared<derived>(4));
//m_s["Name"] = make_shared<derived>(4);
if(4 == m_s.at("Name")->setting){
return EXIT_SUCCESS;
}else{
cout << "setting is " << m_s.at("Name")->setting << " when 4 expected";
return EXIT_FAILURE;
}
}
You cannot initialize base class member in constructor initialization list, but you can call proper base class constructor:
class derived : public base{
public:
derived(const int& s):base{s}{};
};
Your naive "fix" to put member setting into derive class does not fix the issue, but hides it, allow code to compile, but breaking the logic.
For a start, the derived class contains an extra setting member. Getting rid of that revealed that I can't use the derived(const int& s):setting{s}{}; ctor syntax since it refers to a setting member that is inherited.
In the end, using the following fixed my problem:
class correct_derived : public base{
public:
correct_derived(const int& s){
setting = s;
}
};
m_s.insert(make_pair("Name",make_shared<derived>(4)));
if(4 == m_s.at("Name")->setting) {
As far as I can tell you store a Pointer in a map and then compare it to an int (4). You would have to de-reference the stored shared pointer to get its value which you then can compare to '4'. That might be the reason you end up at EXIT_FAILURE.