In the below code, I write a factory method to create objects of a type in a class heirachy.
#include <iostream>
#include <memory>
using namespace std;
enum Type {
_Base, _A, _B, _C
};
class Base{
private:
Type type = _Base;
public:
virtual Type getType(){
return type;
}};
class A : public Base{
private:
Type type = _A;
public:
using Base::Base;
};
class B : public Base{
private:
Type type = _B;
public:
using Base::Base;
};
class C : public Base{
private:
Type type = _C;
public:
using Base::Base;
};
shared_ptr<Base> letterFactory(Type which){
shared_ptr<Base> base = make_unique<Base>(Base());
switch (which){
case _A:
base = make_unique<Base>(A());
case _B:
base = make_unique<Base>(A());
case _C:
base = make_unique<Base>(C());
}
return base;
}
int main(){
shared_ptr<Base> instanceOfA = letterFactory(_A);
cout << instanceOfA->getType() << endl;
shared_ptr<Base> instanceOfB = letterFactory(_B);
cout << instanceOfB->getType() << endl;
shared_ptr<Base> instanceOfC = letterFactory(_C);
cout << instanceOfC->getType() << endl;
return 0;
};
The output is
0
0
0
How can I make the output
1
2
3
Your factory is a bit flawed and your getType() function is not overridden in the derived classes. I guess you wanted to do something along this lines:
#include <iostream>
#include <memory>
using namespace std;
enum Type {
_Base, _A, _B, _C
};
class Base{
public:
virtual ~Base() = default;
virtual Type getType() const {
return _Base;
};
};
class A : public Base{
public:
virtual Type getType() const override {
return _A;
};
};
class B : public Base{
public:
virtual Type getType() const override {
return _B;
};
};
class C : public Base{
public:
virtual Type getType() const override {
return _C;
};
};
unique_ptr<Base> letterFactory(Type which){
switch (which){
case _Base:
return make_unique<Base>();
case _A:
return make_unique<A>();
case _B:
return make_unique<B>();
case _C:
return make_unique<C>();
}
return nullptr;
}
int main(){
shared_ptr<Base> instanceOfA = letterFactory(_A);
cout << instanceOfA->getType() << endl;
shared_ptr<Base> instanceOfB = letterFactory(_B);
cout << instanceOfB->getType() << endl;
shared_ptr<Base> instanceOfC = letterFactory(_C);
cout << instanceOfC->getType() << endl;
return 0;
};
Notice that we got rid of the type member completely and instead properly overrode the getType() function. Furthermore, factory functions like this usually return unique_ptr (which can be implicitly converted to shared_ptr if you really want to).
Your Base class has a member type and a virtual member function getType() that returns the value of the member type. Your classes A, B, and C derive from Base. That means they all have a Base subobject. That subobject contains the member Base::type. In addition, they all also add another member type that is then not ever used by anything. Also, none of them override the getType method either. So whenever you call
instanceOfX->getType()
even if instanceOfX points to an instance of one of the derived classes, since none of the derived classes overrite getType, you'll end up calling Base::getType, which will return the value of Base::type, which is always _Base…
What you actually wanted was probably something along the lines of:
struct Base
{
virtual Type getType() const = 0;
protected:
Base() = default;
Base(Base&&) = default;
Base(const Base&) = default;
Base& operator =(Base&&) = default;
Base& operator =(const Base&) = default;
~Base() = default;
};
class A : public Base
{
public:
Type getType() const override { return _A; }
};
class B : public Base
{
public:
Type getType() const override { return _B; }
};
class C : public Base
{
public:
Type getType() const override { return _C; }
};
Note that this is almost certainly bad design. The only purpose such a getType method could serve is so that client code can find out the concrete type of the object that a Base* it got is pointing to. If you ever need this information, your design violates the Liskov Substitution principle…
Apart from all that, note that _Base, _A, _B, and _C are reserved names [lex.name]/3 that you're not supposed to use in C++ code…
I refactored your code a bit just to apply some of the best practices:
use enum class instead of the raw enum because enum class represents a scoped enumeration type and it is also strongly typed which means you cannot convert it that easily to integer as the raw enum (that's why we have to_integral template function)
prefer not to use using namespace std; because it imports the entirety of the std namespace into the current namespace of the program
also, I think you wanted to use std::make_shared instead of std::make_unique
#include <memory>
#include <iostream>
enum class Type : int {
_Base = 0,
_A = 1,
_B = 2,
_C = 3
};
class Base{
private:
Type type = Type::_Base;
public:
virtual Type getType(){
return type;
}
};
class A : public Base{
private:
Type type = Type::_A;
public:
virtual Type getType() override {
return type;
}
};
class B : public Base{
private:
Type type = Type::_B;
public:
virtual Type getType() override {
return type;
}
};
class C : public Base{
private:
Type type = Type::_C;
public:
virtual Type getType() override {
return type;
}
};
std::shared_ptr<Base> letterFactory(Type which){
switch (which){
case Type::_A:
return std::make_shared<A>();
case Type::_B:
return std::make_shared<B>();
case Type::_C:
return std::make_shared<C>();
default:
return std::make_shared<Base>(Base());
}
}
template <typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value,
typename std::underlying_type<Enum>::type>::type
to_integral(Enum const& value) {
return static_cast<typename std::underlying_type<Enum>::type>(value);
}
int main(){
std::shared_ptr<Base> instanceOfA = letterFactory(Type::_A);
std::cout << to_integral(instanceOfA->getType()) << std::endl;
std::shared_ptr<Base> instanceOfB = letterFactory(Type::_B);
std::cout << to_integral(instanceOfB->getType()) << std::endl;
std::shared_ptr<Base> instanceOfC = letterFactory(Type::_C);
std::cout << to_integral(instanceOfC->getType()) << std::endl;
return 0;
};
Live example
Related
I have a base class B with derived classes X, Y and Z (in fact, more than 20 derived classes). Each class has a tag() function that identifies which (derived) class it is. My program stores instances of the derived classes as pointers in a vector defined as vector<B*>. Each derived class may appear in this vector 0..n times.
I would like to have a function that looks through the vector for instances of a derived type and returns a new vector with the type of the derived class, eg
#include <vector>
using namespace std;
class B {
public:
// ...
virtual int tag() {return 0xFF;};
};
class X : public B {
// ...
int tag() {return 1;};
vector<X*> find_derived(vector<B*> base_vec) {
vector<X*> derived_vec;
for (auto p : base_vec) {
if (p->tag() == tag()) {
derived_vec.push_back((X*) p);
}
}
return derived_vec;
}
};
Obviously I don't want to have to define find_derived in each derived class but I don't see how to do this as a virtual function. Currently I am doing it using a macro but, since I am learning C++, I woudl prefer a method that used language constructs rather than those in the pre-processor. Is there another way?
One possibility:
template <typename D>
class FindDerivedMixin {
public:
vector<D*> find_derived(const vector<B*>& base_vec) {
int my_tag = static_cast<D*>(this)->tag();
vector<D*> derived_vec;
for (auto p : base_vec) {
if (p->tag() == my_tag) derived_vec.push_back(static_cast<D*>(p));
}
return derived_vec;
}
};
class X : public B, public FindDerivedMixin<X> {};
Like the previous answer, what you need is some template programming.
This is an example without mixin though:
#include <vector>
#include <iostream>
#include <type_traits>
#include <string>
//-----------------------------------------------------------------------------
// Base class
class Base
{
public:
virtual ~Base() = default;
// pure virtual method to be implemented by derived classes
virtual void Hello() const = 0;
protected:
// example of a constuctor with parameters
// it is protected since no instances of Base
// should be made by accident.
explicit Base(const std::string& message) :
m_message(message)
{
}
// getter for private member variable
const std::string& message() const
{
return m_message;
}
private:
std::string m_message;
};
//-----------------------------------------------------------------------------
// Class which contains a collection of derived classes of base
class Collection
{
public:
Collection() = default;
virtual ~Collection() = default;
// Add derived classes to the collection.
// Forward any arguments to the constructor of the derived class
template<typename type_t, typename... args_t>
void Add(args_t&&... args)
{
// compile time check if user adds a class that's derived from base.
static_assert(std::is_base_of_v<Base, type_t>,"You must add a class derived from Base");
// for polymorphism to work (casting) we need pointers to derived classes.
// use unique pointers to ensure it is the collection that will be the owner of the
// instances
m_collection.push_back(std::make_unique<type_t>(std::forward<args_t>(args)...));
}
// Getter function to get derived objects of type_t
template<typename type_t>
std::vector<type_t*> get_objects()
{
static_assert(std::is_base_of_v<Base, type_t>, "You must add a class derived from Base");
// return non-owning pointers to the derived classes
std::vector<type_t*> retval;
// loop over all objects in the collection of type std::unique_ptr<Base>
for (auto& ptr : m_collection)
{
// try to cast to a pointer to derived class of type_t
type_t* derived_ptr = dynamic_cast<type_t*>(ptr.get());
// if cast was succesful we have a pointer to the derived type
if (derived_ptr != nullptr)
{
// add the non-owning pointer to the vector that's going to be returned
retval.push_back(derived_ptr);
}
}
return retval;
}
private:
std::vector<std::unique_ptr<Base>> m_collection;
};
//-----------------------------------------------------------------------------
// some derived classes for testing.
class Derived1 :
public Base
{
public:
explicit Derived1(const std::string& message) :
Base(message)
{
}
virtual ~Derived1() = default;
void Hello() const override
{
std::cout << "Derived1 : " << message() << "\n";
}
};
//-----------------------------------------------------------------------------
class Derived2 :
public Base
{
public:
explicit Derived2(const std::string& message) :
Base(message)
{
}
virtual ~Derived2() = default;
void Hello() const override
{
std::cout << "Derived2 : " << message() << "\n";
}
};
//-----------------------------------------------------------------------------
int main()
{
Collection collection;
collection.Add<Derived1>("Instance 1");
collection.Add<Derived1>("Instance 2");
collection.Add<Derived2>("Instance 1");
collection.Add<Derived2>("Instance 2");
collection.Add<Derived1>("Instance 3");
// This is where template programming really helps
// the lines above where just to get the collection filled
auto objects = collection.get_objects<Derived1>();
for (auto& derived : objects)
{
derived->Hello();
}
return 0;
}
Suppose I have a base class that is an abstract interface, and two derived classes, which inherit a certain state from the base class. I want to change which derived class I'm using at run-time, but I want to preserve the shared state.
class Base{
public:
virtual void abstract() = 0;
SharedState ss;
};
class Der1 : public Base{
Der1() = default;
virtual void abstract() {//bla bla};
Der1(SharedState &s){
ss = s;};
};
class Der2 : public Base{
Der2() = default;
virtual void abstract(){//bla bla 2};
Der2(SharedState &s){
ss = s;};
};
struct SharedState{
int x,y,z;
float x1,y1,z1;
//etc...
}
I my handler code, I have a smart pointer that changes behaviour based on class type at run-time, hence the shared state constructor.
//driver code
std::unique_ptr<Base> ptr = std::make_unique<Der1>();
I'm planning to change the type, but with such a constructor I can preserve the state. However it is highly annoying to preface every member of the shared state with ss., is there a way to avoid this, perhaps with a using declaration of some sort?
Edit: I know I can move the shared state in the base and make it static, but that leads to performance drops when I'm not using this interface.
This is an ugly answer, but is an answer, solves the "ss" problem and can be usefull.
I overloaded the operator [] to directly return the values of your struct
struct SharedState{
int x,y,z;
float x1,y1,z1;
//etc...
};
class Base{
public:
virtual void abstract() = 0;
SharedState ss;
public:
int& operator[](const std::string rhs)
{
if(rhs == "x") //Here you will manage all the struct members, probably a map
return this->ss.x; // return the result by reference
}
};
class Der1 : public Base{
void abstract() override { };
public:
Der1(SharedState &s){
ss = s;};
};
class Der2 : public Base{
void abstract() override { };
public:
Der2(SharedState &s){
ss = s;};
};
int main()
{
SharedState ss;
ss.x = 100;
std::unique_ptr<Base> ptr = std::make_unique<Der1>(ss);
std::cout << (*ptr)["x"] << std::endl;
(*ptr)["x"] = 5; // You can change it too
std::cout << (*ptr)["x"] << std::endl;
std::unique_ptr<Base> ptr2 = std::make_unique<Der2>(ptr->ss);
std::cout << (*ptr2)["x"] << std::endl;
}
This question already has answers here:
c++ Function to return an enum?
(4 answers)
Closed 7 years ago.
i am having trouble with the following:
i need to use enum to enumerate 4 inherited classes (at this point they have no difference between them other the the enum) and then return the type via a virtual function called "whoAmI", i don't understand the syntax as to how i would do the return part
the following is the relevant code;
in class.h
virtual void whoAmI();
enum gettype { easyTile, cropTile, waterTile, mediumTile};
in class.cpp
void tile::whoAmI()
{
}
You can change the return type of your function to the name of your enum, then use = 0 to declare the base class is pure virtual.
class ITile
{
public:
enum class EType { easy, crop, water, medium };
virtual EType whoAmI() const = 0;
};
Then the derived classes can override this method to return the correct enum type, for example
class EasyTile : public ITile
{
public:
EasyTile() = default;
EType whoAmI() const override { return EType::easy; }
};
class CropTile : public ITile
{
public:
CropTile() = default;
EType whoAmI() const override { return EType::crop; }
};
So as an example (live demo)
int main()
{
std::vector<std::unique_ptr<ITile>> tiles;
tiles.emplace_back(new EasyTile);
tiles.emplace_back(new CropTile);
for (auto const& tile : tiles)
{
std::cout << static_cast<int>(tile->whoAmI()) << std::endl;
}
}
Will output
0
1
You can easily do it like that:
class TileBase
{
public:
enum Type { easyTile, cropTile, waterTile, mediumTile };
virtual Type whoAmI() const = 0;
virtual ~TileBase() = default;
};
class EasyTile : public TileBase
{
Type whoAmI() const override { return easyTile; }
};
You see, you need to specify the enum Type as return type instead of void.
#include <iostream>
using namespace std;
class Tile{
public:
enum getType { easyTile, cropTile, waterTile, mediumTile};
virtual getType whoAmI(){}
};
class easyTile:public Tile{
public:
getType whoAmI(){return getType::easyTile;}
};
class cropTile: public Tile{
public:
virtual getType whoAmI(){return getType::cropTile;}
};
class waterTile: public Tile{
public:
virtual getType whoAmI(){return getType::waterTile;}
};
class mediumTile: public Tile{
public:
virtual getType whoAmI(){ return getType::mediumTile;}
};
int main() {
Tile *T = new cropTile;
cout << T->whoAmI() << endl;
delete T;
return 0;
}
Output : 1
I want to create a class that implements two interfaces that have functions with a same name that differ only by their return values. How can I do this correctly?
template<class T>
class IBase
{
public:
virtual T Method() = 0;
};
class Derived : public IBase<int>, public IBase<char> {
public:
int _value;
virtual int IBase<int>::Method();
virtual char IBase<char>::Method();
};
int Derived::Method() {
return _value;
}
char Derived::Method() {
return _value;
}
Here are the errors that I get:
error C2555: 'Derived::Method: overriding virtual function return type differs and is not covariant from 'IBase<int>::Method
error C2556: 'int Derived::Method(void)' : overloaded function differs only by return type from 'char Derived::Method(void)'
error C2371: 'Derived::Method: redefinition; different basic types
error C2084: function 'char Derived::Method(void)' already has a body
In C# it's pretty easy to do this without any ambiguities using nearly same syntax (called explicit interface implementation):
class Derived : IBase<int>, IBase<char> {
int _value;
int IBase<int>.Method() {
return _value;
}
char IBase<char>.Method();
return _value;
}
};
Explicitly implementations are private and thus cannot be used directly on variables of class Derived. They are still very usable though as you can cast the Derived to one of the interfaces to use the implementation:
var d = new Derived();
((IBase<int>)d).Method();
This can be rather useful. A class can implement ICanConvertTo many times to enable different conversions.
With virtual in Derived
#include <iostream>
template<typename T>
class IBase
{
public:
virtual T method() = 0;
};
template<typename T>
class WrapBase : public IBase<T>
{
protected:
virtual T do_method(T*) = 0;
public:
virtual T method() {
return do_method((T*)0);
}
};
class Derived : public WrapBase<char>, public WrapBase<int>
{
protected:
virtual char do_method(char*) { return 'A'; };
virtual int do_method(int*) { return 1; };
};
Removing virtual in Derived - Thanks to DyP:
include <iostream>
template<typename T>
class IBase
{
public:
virtual T method() = 0;
};
template<typename D, typename T>
class WrapBase : public IBase<T>
{
public:
virtual T method();
};
class Derived : public WrapBase<Derived, char>, public WrapBase<Derived, int>
{
friend class WrapBase<Derived, char>;
friend class WrapBase<Derived, int>;
protected:
char do_method(char*) { return 'A'; };
int do_method(int*) { return 1; };
};
template<typename D, typename T>
inline T WrapBase<D, T>::method() {
return static_cast<D*>(this)->do_method((T*)0);
}
Test:
int main () {
Derived d;
IBase<char>& c = d;
IBase<int>& i = d;
std::cout << c.method() << " != " << i.method() << std::endl;
}
Comment: Mixing static and dynamic polymorphism might be a bad design.
Function can not differ only by return value, because the compiler has no way to distinguish them. Consider:
long x;
Derived d;
x = d.Method();
both the char and the int variant are possible to convert to an long - which one should it use?
Edit:
If you want to define conversions, the typical case is to define a cast-operator, e.g.
class X
{
float x;
public:
X(float f) : x(f) {}
operator int() { return static_cast<int>(x); }
operator char() { return static_cast<char>(x); }
float getX() { return x; }
};
and then call it as:
X x(65.3);
int y = x;
char z = x;
cout << "x.f=" << x.getF() << " as char:" << z << " as int:" << y << endl;
Returned value type is not part of the function (method) signature.
So your two methods are seen as the same method (so the redefinition error).
So you can't do what you want. your method should have different signature.
I need a base class that gives me primitive type of data's pointer. I add a function in it. I derived types of class. I used void * to support all primitive types as a return type but it is like old C days. It is not good for OOP. Does one have an suggestion to do in a proper way in OOP?
#include <iostream>
class base {
public:
virtual void *getPtr() = 0;
virtual ~base() {};
};
class derivedAType : public base {
protected:
int _i;
public:
derivedAType(int i): _i(0) { _i = i; };
virtual ~derivedAType() {}
virtual void *getPtr() {
return static_cast<void *>(&_i);
}
};
class derivedBType : public base {
protected:
short _s;
public:
derivedBType(short s): _s(0) { _s = s; };
virtual ~derivedBType() {}
virtual void *getPtr() {
return static_cast<void *>(&_s);
}
};
int main()
{
base *b1 = new derivedAType(1203912);
base *b2 = new derivedBType(25273);
std::cout << "b1 : " << *(static_cast<int *>(b1->getPtr()))
<< "\nb2 : " << *(static_cast<short *>(b2->getPtr()))
<< std::endl;
delete b2;
delete b1;
return 0;
}
Make the base class a template class with the data type as the template variable
template<typename DataType>
class base {
virtual DataType* getPtr() = 0;
//...
};
and
class derivedAType : public base<int>
But this changes base class to a template class which means you cant store them together, base<int> is different from base<short>
If this isnt acceptable, the other options is just a tad bit cleaner than your code but abt the same, refer to this question. Basically derived class return types can reflect their true type and i think it should get automatically converted to void*, so you dont have to manually cast the pointer.
Not sure about your problem. But maybe a double callback can help:
class Callback {
public:
virtual void do_int( int i ) const = 0;
virtual void do_short( short s ) const = 0;
/* ... */
}
class base {
public:
virtual void do_stuff(const Callback & c); /* will need a more telling name */
virtual ~base() {};
};
class derivedAType : public base {
protected:
int _i;
public:
derivedAType(int i): _i(0) { _i = i; };
virtual ~derivedAType() {}
virtual void do_stuff(const Callback & c) {
c.do_int( _i );
}
};
class derivedBType : public base {
protected:
short _s;
public:
derivedBType(short s): _s(0) { _s = s; };
virtual ~derivedBType() {}
virtual void do_stuff( const Callback & c) {
c.do_short( _s );
}
};
class print_callback : public Callback {
public:
virtual void do_int( int i ) const { std::cout << i; }
virtual void do_short( short s ) const { std::cout << s; }
}
int main() {
base *b1 = new derivedAType(1203912);
base *b2 = new derivedBType(25273);
std::cout << "b1 : ";
b1->do_stuff(print_callback());
std::cout << "\nb2 : ";
b2->do_stuff(print_callback());
std::cout << std::endl;
delete b2;
delete b1;
return 0;
}
Of course you can simplify this by just storing the created print callback, and using it twice.