Is it possible to achieve behaviour demonstrated below with virtual functions? And if it's not the correct way to go about polymorphism then what would be the correct way in this example?
class Base_
{
float x;
float y;
float z;
public:
Base_(float xx=0, float yy=0, float zz=0)
{
x = xx;
y = yy;
z = zz;
}
virtual void SetParemeters(what here?)=0; //Different number of arguments
};
class Derived_1 :public Base_
{
float r;
public:
Derived_1(float rr=1, float xx=0, float yy=0, float zz=0):Base_(xx,yy,zz)
{
r=rr;
}
virtual void SetParemeters(float v1) //Different number of arguments
{
r=v1;
}
};
class Derived_2 :public Base_
{
float k;
float w;
public:
Derived_2(float kk=1, float ww=1,float xx=0, float yy=0, float zz=0):Base_(xx,yy,zz)
{
k=kk;
w=ww;
}
virtual void SetParemeters(float v1, float v2) //Different number of arguments
{
k=v1;
w=v2;
}
};
int main()
{
Derived_1 d1;
Derived_2 d2;
Base_ *ptr;
ptr = &d1;
ptr -> SetParemeters(one argument)
ptr = &d2;
ptr-> SetParemeters(one or two arguments)
return 0;
}
And even if I managed to achieve that, how can I set only second parameter (k) here: ptr-> SetParemeters(one or two arguments)?
I searched for answers but I only found answers to specific scenarios which made the whole thing difficult for me to understand.
Yes, make Base_::SetParameters takes two (optional) arguments:
class Base_
{
// [...]
public:
virtual void SetParemeters(float=0f, float=0f)=0;
};
Derived_1::SetParameters just ignores the first one:
class Derived_1 :public Base_
{
// [...]
virtual void SetParemeters(float v1, float=0f)
{
r=v1;
}
};
while Derived_2 takes the both of them
class Derived_2 :public Base_
{
// [...]
virtual void SetParemeters(float v1, float v2)
{
k=v1;
w=v2;
}
};
demo: https://coliru.stacked-crooked.com/a/c528ffff005df5b9
Note though, this significantly reduces the interest of virtual functions...
Derived_1 d1;
Derived_2 d2;
Base_ *ptr;
ptr = &d1;
ptr->SetParameters(one argument)
ptr = &d2;
ptr->SetParameters(one or two arguments)
The way how this code is written implies that you have knowledge about two things:
at the time of the first call to SetParameters(), ptr points to an object of type Derived_1
at the second call, it points to an object of type Derived_2.
This in turn means that you know the static types -- and in fact, you need to, due to the different signatures.
For such a scenario, dynamic polymorphism is not the right choice, because its premise is that you can talk to different implementations (overridden methods) using a uniform access (calling the virtual base method).
So, if you have this knowledge at compile time, simply use non-virtual method calls.
However, there are similar scenarios where you may actually be interested in supporting different signatures at runtime, for example if you load configuration dynamically. Here is an example, where not the number, but the types of arguments differ.
class Car : public Vehicle
{
virtual void addFuel(const Petrol& f) override;
};
class Airplane : public Vehicle
{
virtual void addFuel(const Kerosene& f) override;
};
How would then the base function look?
class Vehicle
{
virtual ~Vehicle() {} // don't forget this!
virtual void addFuel(const /* which type? */& f) = 0;
};
One option is to make the fuel type a hierarchy as well (both Kerosene and Petrol inherit the Fuel class):
class Vehicle
{
virtual ~Vehicle() {}
virtual void addFuel(const Fuel& f) = 0;
};
However, in this case, each implementation would need to either rely on the fact it's passed the right fuel, or check the type at runtime.
class Airplane : public Vehicle
{
virtual void addFuel(const Fuel& f) override
{
if (auto* k = dynamic_cast<const Kerosene*>(&f))
{
// use concrete fuel
}
}
};
You can make SetParameters a variadic function and have the polymorphic interface be internal, providing the writeable parameters in a generic form (here as a vector of pointers to them):
class Base_
{
float x;
float y;
float z;
public:
Base_(float xx=0, float yy=0, float zz=0)
{
x = xx;
y = yy;
z = zz;
}
virtual std::vector<float*> getAllExtraParameters() = 0;
template<class ... Ts>
void SetExtraParameters(Ts&& ... ts)
{
auto extras = getAllExtraParameters();
if (sizeof...(ts) > extras.size())
throw std::runtime_error("Too many parameters given!");
// Fold expression - could be implemented differently in C++ < 17.
int index = 0;
((*extras[index++] = ts), ...);
}
};
class Derived_1 :public Base_
{
float r;
public:
Derived_1(float rr=1, float xx=0, float yy=0, float zz=0):Base_(xx,yy,zz)
{
r=rr;
}
std::vector<float*> getAllExtraParameters() override
{
return { &r };
}
};
class Derived_2 :public Base_
{
public:
float k;
float w;
Derived_2(float kk=1, float ww=1,float xx=0, float yy=0, float zz=0):Base_(xx,yy,zz)
{
k=kk;
w=ww;
}
std::vector<float*> getAllExtraParameters() override
{
return { &k, &w };
}
};
Demo and tests: https://godbolt.org/z/ofXnuH
Related
I'm trying to allow a class to implement an interface, where the interface is templated to either allow an update internally or not. The code looks like this and works if the implementation is within the class declaration. If it is moved out (as shown here), I get a compiler error on Visual Studio 2019, and I can't understand why. All help is appreciated!
The following code will not compile. If the out of class implementation and headers are modified to just use the code I commented out, it compiles and works as expected.
#include <atomic>
#include <cstdint>
#include <memory>
#include <iostream>
#include <string>
enum class EntryType { Read, ReadUpdate };
template <EntryType Type>
class IXQ
{
public:
virtual float GetValue() = 0;
};
class X : public IXQ<EntryType::Read>, public IXQ<EntryType::ReadUpdate>
{
public:
float IXQ<EntryType::Read>::GetValue();
/*
float IXQ<EntryType::Read>::GetValue()
{
return _x;
}
*/
float IXQ<EntryType::ReadUpdate>::GetValue();
/*
float IXQ<EntryType::ReadUpdate>::GetValue() {
_counter++;
return _x;
}
*/
float _x = 10.0F;
std::atomic<std::int32_t> _counter = 0;
};
float X::IXQ<EntryType::Read>::GetValue()
{
return _x;
}
float X::IXQ<EntryType::ReadUpdate>::GetValue()
{
_counter++;
return _x;
};
int main(int argc, char* argv[])
{
{
auto k = std::make_unique<X>();
auto ptrQ = static_cast<IXQ<EntryType::Read>*>(k.get());
std::cout << std::to_string(ptrQ->GetValue()) << std::endl;
std::cout << k->_counter.load() << std::endl;
}
{
auto k = std::make_unique<X>();
auto ptrQ = static_cast<IXQ<EntryType::ReadUpdate>*>(k.get());
std::cout << std::to_string(ptrQ->GetValue()) << std::endl;
std::cout << k->_counter.load() << std::endl;
}
return 0;
}
1. Microsoft-specific syntax
The syntax you're using to override GetValue() is not standard c++.
class X : public IXQ<EntryType::Read> {
public:
float IXQ<EntryType::Read>::GetValue() { /* ... */ }
}
This is a Microsoft-Specific Extension for C++ called Explicit Overrides (C++) and is intended to be used with __interfaces (also a microsoft-specific extension to c++).
__interfaces do not officially support c++ templates due to them being intended mostly for COM Interfaces, e.g.:
[ object, uuid("00000000-0000-0000-0000-000000000001"), library_block ]
__interface ISomething {
// properties
[ id(0) ] int iInt;
[ id(5) ] BSTR bStr;
// functions
void DoSomething();
};
It's suprising that float IXQ<EntryType::Read>::GetValue() { /* ... */ } works at all.
2. Standard C++-compliant solutions
In standard C++ the overriden function is determined by the name & arguments alone, so your only option is to override both of them.
e.g.:
class X : public IXQ<EntryType::Read>, public IXQ<EntryType::ReadUpdate>
{
public:
// will be the implementation for both IXQ<EntryType::Read> & IXQ<EntryType::ReadUpdate>
float GetValue() override;
};
float X::GetValue() {
/* ... */
}
Another standard-compliant way would be to create 2 classes that inherit from the given interfaces & then let X inherit from both of them:
class XRead : public IXQ<EntryType::Read> {
public:
float GetValue() override { /* ... */ }
};
class XReadUpdate : public IXQ<EntryType::ReadUpdate> {
public:
float GetValue() override { /* ... */ }
};
class X : public XRead, public XReadUpdate {
/* ... */
};
If you want to share state between XRead & XReadUpdate, you'd have to introduce another level, e.g.:
class XBase {
public:
virtual ~XBase() = default;
protected:
float value;
};
class XRead : public virtual XBase, public IXQ<EntryType::Read> {
float GetValue() override { return value; }
};
class XReadUpdate : public virtual XBase, public IXQ<EntryType::ReadUpdate> {
float GetValue() override { return value; }
};
class X : public XRead, public XReadUpdate {
/* ... */
};
3. Possible recommendations for API Design
Keep in mind though that this type of API design will be rather complicated to use, because you always need to cast to the specific interface first before you can call the function because X{}.GetValue() would be ambigous.
e.g.:
X x;
IXQ<EntryType::Read>& read = x;
std::cout << read.GetValue() << std::endl;
IXQ<EntryType::ReadUpdate>& update = x;
std::cout << update.GetValue() << std::endl;
// this is *not* possible, GetValue() is ambigous
// std::cout << x.GetValue() << std::endl;
I'd recommend separating both interfaces & using different method names, e.g.: godbolt example
struct IXQReadonly {
virtual ~IXQReadonly() = default;
virtual float GetValue() = 0;
};
struct IXQ : IXQReadonly {
virtual float GetValueUpdate() = 0;
};
class X : public IXQ {
public:
X() : value(0.0f), counter(0) { }
float GetValue() override { return value; }
float GetValueUpdate() override {
++counter;
return value;
}
private:
float value;
std::atomic<int> counter;
};
This comes with a whole set of benefits:
You can call GetValue() / GetValueUpdate() directly on X, no need to convert to an interface first
X x;
x.GetValue();
x.GetValueUpdate();
It is immediately clear from the method name if it will update the counter or not
A function that is given an IXQ can call a function that expects IXQReadonly, but not the other way round: (so you can "downgrade" a read-write interface to readonly, but not "upgrade" a readonly interface to read-write)
void bar(IXQReadonly& r) { r.GetValue(); /* we can't do GetValueUpdate() here */ }
void foo(IXQ& x) { bar(x); x.GetValueUpdate(); }
Additionally remember to declare the destructor as virtual (at least in the top-most class / interface), otherwise funny things tend to happen if you try to delete an instance of X through a pointer to one of its bases / interfaces.
I think this can be solved by adding an intermediate layer of classes, let's say X_Read and X_ReadUpdate from which X can inherit.
IXQ
/ \
X_Read X_ReadUpdate
\ /
X
The trick is having those intermediate classes implement GetValue by calling two virtual pure methods, let's say GetValueRead and GetValueReadUpdate respectively. This way, X still inherits from IXQ<EntryType::Read> and IXQ<EntryType::ReadUpdate>, but comes to implement GetValueRead and GetValueReadUpdate, two methods with clear and distinct interfaces.
[Demo]
template <EntryType Type>
class IXQ
{
public:
virtual float GetValue() = 0;
};
class X_Read : public IXQ<EntryType::Read>
{
public:
virtual float GetValue() override { return GetValueRead(); };
virtual float GetValueRead() = 0;
};
class X_ReadUpdate : public IXQ<EntryType::ReadUpdate>
{
public:
virtual float GetValue() override { return GetValueReadUpdate(); };
virtual float GetValueReadUpdate() = 0;
};
class X : public X_Read, public X_ReadUpdate
{
public:
virtual float GetValueRead() override { return _x; }
virtual float GetValueReadUpdate() { _counter++; return _x; };
float _x{10.0f};
std::atomic<std::int32_t> _counter{};
};
// Outputs:
// 10.000000
// 0
// 10.000000
// 1
I have a virtual inheritance example like below:
class Polygon {
public:
virtual double area() = 0;
};
class Rectangle : public virtual Polygon {
double a, b;
public:
Rectangle(double a, double b) {
this->a = a;
this->b = b;
}
double area() { return a * b; }
};
class Rombus : public virtual Polygon {
double a, h;
public:
Rombus(double a, double h) {
this->a = a;
this->h = h;
}
double area() { return a * h; }
};
class Square : public Rectangle, public Rombus {
public:
Square(double a) : Rectangle(a, a), Rombus(a, a) {}
};
It is one of requirements that Suare has to inherit from Rectangle and Rombus. That's why I use virtual inheritance.
But then I got an error:
override of virtual function "Polygon::area" is ambiguous
'Square': ambiguous inheritance of 'double Polygon::area(void)'
What am I doing wrong?
The error message is:
'Square': ambiguous inheritance of 'double Polygon::area(void)'
It should be obvious why: there are two implementations!
double area() { return a * b; } // in Rectangle
double area() { return a * h; } // in Rhombus
Square inherits both of them, so there is no possible way the compiler could know which to use.
You can "fix" it by overriding area() in Square as well.
This design is deficient from the start: a Square should only contain a single member, its width/height. But yours contains four members, all of which will always have the same value!
I want to create 2 kind of classes.
the classes will have similar function "set", but the set funct will get "int" in class B and double in class C. (A is abstract calss but it does not require).
What do I need to do?
class A{
int x;
public:
A (int t=1): x(t){}
virtual void set ()=0;
}
class B: public A{
int y;
public:
virtual void set (int y);
};
class C: public A{
double y;
public:
virtual void set (double y);
};
void main ()
{
B b; //error
C c; //error
}
Create a single template class and instantiate which ever you need at the time, or typedef B and C from the template class:
template< typename T > class A
{
public: A() : mValue() {}
void Set( T value ) { mValue = value; }
private: T mValue;
};
typedef A< int > B;
typedef A< double > C;
There are pretty many variants to solve this, but first of all, virtual function has to have the same signature (there could be an exception, but that's irrelevant for your case). So solution is to have and argument(s) that will solve all cases. There are variants:
Pass all variants to the function, and use only particular one:
class A {
public:
virtual void set( int, double ) = 0;
};
class B {
int y;
public:
virtual void set( int val, double ) { y = val; }
};
class C {
double y;
public:
virtual void set( int , double val ) { y = val; }
};
This is not very good solution and does not scale well, so we can use union:
Union Arg {
int i;
double d;
};
class A {
public:
virtual void set( Arg a ) = 0;
};
// derived classes are trivial, so omitted
Union is not type safe, so we can use boost::variant instead
Another solution to have another hierarchy for parameter:
struct Arg {
virtual ~Arg();
};
struct IntArg : Arg {
int m_value;
};
struct DoubleArg : Arg {
double m_value;
};
class A {
virtual void set( const Arg &a ) = 0;
};
class B {
int y;
public:
virtual void set( const Arg &a ) { y = dynamic_cast<const IntArg &>( a ).m_value; }
};
class C {
double y;
public:
virtual void set( const Arg &a ) { y = dynamic_cast<const DoubleArg &>( a ).m_value; }
};
You can use static_cast and then you will not need virtual destructor in Arg, but that is less safe.
These are only some variants, there could be much more, which one suits you best you can only decide based on your program requirements.
Ditch the inheritance and virtual thing. You can't easily access a statically unknown type result via a virtual function. So:
class A
{
private:
int x_;
public:
A( int const t = 1 ): x_( t ) {}
};
class B
: public A
{
private:
int y_;
public:
void set( int const y );
};
class C
: public A
{
private:
double y_;
public:
void set( double const y );
};
int main ()
{
B b; // OK
C c; // OK
}
Note the semicolon at the end of class A and the int main instead of void main.
Such details matter.
Otherwise you can send people who want to help you, on long wild goose chases. And you don't want that, do you? So, make sure the code you post has been accepted by a compiler, except possibly for the troublesome parts that you want to show do not compile.
The trick is to find common parts of B and C, and put them to base class. The stuff that is different should go to constructor parameter of the derived class:
class A {
virtual std::string get() const=0;
virtual void set(std::string s)=0;
};
class B : public A { B(int a) : a(a) { } int a; };
class C : public A { C(float b) : b(b) { } float b; }
To implement the functions, you'll need the following:
void B::set(std::string s) {
stringstream ss(s);
ss >> a;
}
void C::set(std::string s) {
stringstream ss(s);
ss >> b;
}
The functions look the same, but are actually calling different operator>>.
My problem is the following:
int main()
{
Base* derivedobject = new Derived1();
derivedobject->GetProperties()-> ???
return 0;
}
//********************
// BaseClass.h
//********************
struct PropertyStruct
{
int x;
};
class Base
{
public:
Base();
~Base();
virtual PropertyStruct GetProperties() = 0;
private:
};
//********************
// DerivedClass1.h
//********************
struct PropertyStruct
{
int y;
};
class Derived1 : public Base
{
public:
Derived1();
~Derived1();
PropertyStruct GetProperties() { return myOwnDifferentProperties; };
private:
};
//********************
// DerivedClass2.h
//********************
struct PropertyStruct
{
float z;
};
class Derived2 : public Base
{
public:
Derived2();
~Derived2();
PropertyStruct GetProperties() { return myOwnDifferentProperties };
private:
};
If I do it like that I'm going to get an error saying that PropertyStruct is a redefinition. If I use a namespace or rename the struct inside the derived class I am then going to get an error telling me that the return type is not the same as defined by Base.
If I define the virtual functions return type as a pointer it compiles, though the next problem when accessing the function "GetProperties" from the main method (in this example) the base object does not know what variables are inside the struct of the derived class.
Is there any way I can realize this ?
That I can get the different properties of each derived object but using the base class object ?
As others have mentioned, there are ways to achieve your goals here but ultimately you will find yourself writing code like the following:
Base * object = ...;
if object is Derived1 then
get Property1 and do something with it
else if object is Derived2 then
get Property2 and do something with it
This is an anti-pattern in object-oriented programming. You already have a class hierarchy to represent the differences between the various derived types. Rather than extracting the data from your objects and processing it externally, consider adding a virtual function to the base class and letting the derived classes do the processing.
class Base
{
public:
virtual void DoSomething() = 0;
};
class Derived1 : Base
{
public:
void DoSomething()
{
// use myOwnDifferentProperties as necessary
}
private:
PropertyStruct myOwnDifferentProperties;
};
If it's not appropriate to put the required processing in the derived classes (i.e. if it would introduce unwanted responsibilities) then you may want to consider the Visitor Pattern as a way to extend the functionality of your hierarchy.
Since template functions cannot be virtual you can use hierarchy of your properties. It's only one way, no other ways. For get elements of derived Properties you should use virtual getter functions.
struct BaseProp
{
virtual ~BaseProp() { }
virtual boost::any getProperty() const = 0;
};
struct PropertyStruct : BaseProp
{
boost::any getProperty() const { return x; }
private:
int x;
};
struct PropertyStruct2 : BaseProp
{
boost::any getProperty() const { return y; }
private:
float y;
};
class Base
{
public:
virtual std::shared_ptr<BaseProp> GetProperties() const = 0;
virtual ~Base() { }
}
class Derived
{
public:
std::shared_ptr<BaseProp> GetProperties() const { return new PropertyStruct(); }
};
class Derived2
{
public:
std::shared_ptr<BaseProp> GetProperties() const { return new PropertyStruct2(); }
};
You can use template class to do that:
struct PropertyStruct1 {
float f;
};
struct PropertyStruct2 {
int i;
};
template<class T>
class A{
public:
T GetProperties() {return mProps;}
private:
T mProps;
};
int main (int argc, const char * argv[]) {
A<PropertyStruct1> a1;
int f = a1.GetProperties().f;
A<PropertyStruct2> a2;
int i = a2.GetProperties().i;
return 0;
}
For the below code snippet, how do I initialize instances of class Enemy with variables (such as x, y, type)? I have it working correctly, it triggers the instances no matter how many of them I insert... I just need to know the best way of creating an enemy with certain variables that will differ for each of my instances... particularly when some of those variables are in the base class and others are not.
class BaseObject
{
public:
virtual void Render() = 0;
int x;
int y;
};
class Enemy : public BaseObject
{
public:
Enemy() { }
virtual void Render()
{
cout << "Render! Enemy" << endl;
}
typedef std::set<BaseObject *> GAMEOBJECTS;
GAMEOBJECTS g_gameObjects;
int main()
{
g_gameObjects.insert(new Enemy());
g_lootObjects.insert(new Loot());
for(GAMEOBJECTS::iterator it = g_gameObjects.begin();
it != g_gameObjects.end();
it++)
{
(*it)->Render();
}
for(GAMEOBJECTS::iterator it = g_lootObjects.begin();
it != g_lootObjects.end();
it++)
{
(*it)->Render();
}
return 0;
}
Include the arguments in the enemy constructor and Base constructors. You can then use those to initialize the member variables.
class BaseObject
{
public:
BaseObject(int x, int y) : x(x), y(y){ }
virtual void Render() = 0;
int x;
int y;
};
and
class Enemy : public BaseObject
{
public:
Enemy(int x, int y, int foo) : BaseObject(x,y), foo(foo) { }
int foo;
...
};