Sorry for the convoluted title of my question, conceptually it is quite simple but I can't find any good design to do it.
I have a base class accessible by the end user :
class A {
private:
// m is a functor
Base* m;
};
class Base {
public:
virtual void someInterface();
};
class DerivedT1 : public Base {
public:
virtual void someInterface()
{
some_parameter++;
}
private:
int some_parameter; // how to set?
};
class DerivedT2 : public Base {
public:
virtual void someInterface()
{
some_other_parameter += a_third_parameter;
}
private:
double some_other_parameter; // how to set?
double a_third_parameter; // how to set?
};
And I am trying to find the most generic way to set some_parameter and some_other_parameter from A's public interface.
I have thought of giving a number to my parameters but this sounds really ugly.
Is there any beautiful, object-oriented way to do this ?
you want to use A's public interface to set derived class parameters:
you can define a public function In A, which have a Base* parameter:
class A
{
public:
void setter(const Base *p);
{
m = p;
}
};
if you want to set Drived1 you can define a object of Derived1, can pass it to setter;
I think you want to pass value using A's public function, you must know the type of pointer of Base*,so you can pass value by the constructor of Derived1 or Derived2!
I nothing else works, you could always use a dynamic cast:
DerivedT1 *d1 = dynamic_cast<DerivedT1>(m);
if (d1 != nullptr)
{
// do something with derived 1
}
else
{
DerivedT2 *d2 = dynamic_cast<DerivedT2>(m);
if (d2 != nullptr)
{
// do something with derived 2
}
}
But if you need that, it's usually a sign that there is something wrong with your design.
If you want to do something along these lines
A a; a.setAlgorithmFamily(Algorithm::Type1);
a.getAlgorithmImplementation().setSomeParameter(34);
This is a quick and kind of dirty example of how you could do it. A::setAlgorithmType is basically a factory pattern in it's simplest form.
nclude <iostream>
using namespace std;
class Algorithm {
public:
virtual void setParameter(int value) = 0;
};
class AlgoX : public Algorithm {
int mX;
public:
void setParameter(int value) {
cout <<"Setting X to " <<value <<endl;
mX = value;
}
};
class AlgoY : public Algorithm {
int mY;
public:
void setParameter(int value) {
cout <<"Setting Y to " <<value <<endl;
mY = value;
}
};
class A {
public:
void setAlgorithmType(std::string type) {
cout <<"Now using algorithm " <<type <<endl;
if(type == "X")
mAlgorithm = new AlgoX();
else if(type == "Y")
mAlgorithm = new AlgoY();
}
Algorithm* getAlgorithmImplementation() { return mAlgorithm; }
private:
Algorithm* mAlgorithm;
};
int main(int argc, char** argv) {
A a;
a.setAlgorithmType("X");
a.getAlgorithmImplementation()->setParameter(5);
return 0;
}
This gives:
Now using algorithm X
Setting X to 5
Related
I learn C++ OOP-paradigm and want to ask related question:
Assumption
We have a base class:
class Base {
public:
virtual SomeType PowerMethod() { return SomeType{} };
}
We have a variable target and subclass which realizes some calculations with target variable based on the constructor's parameter (simple calculations or complicated calcs):
class Calc : public Base {
public: // using only public access to simplify real code structure
SomeType target;
void Simple() { target = 1; };
void Complex(){ target = 10000; };
explicit Calc(bool isSimple) {
if(isSimple)
Simple();
else
Complex();
}
};
Question
How to optimally realize two classes which based on different methods (Simple or Complex) but provide the same functionality of PowerMethod()?
My solution
class SimpleCalc : public Calc {
bool isSimple = true;
public:
SomeType PowerMethod() override {
Calc CalcInstance(isSimple);
return CalcInstance.target;
};
};
class ComplexCalc : public Calc {
bool isSimple = false;
public:
SomeType PowerMethod() override {
Calc CalcInstance(isSimple);
return CalcInstance.target;
};
};
This solution is pretty "ugly" and I want to ask you how to make it more readable.
Thank you!
I think that in your code, you didn't mean to craete a new Calc object, but instead call it on the superclass. This can be done like so:
Calc::Simple();
You can override the method PowerMethod, but still call the superclass's code:
virtual SomeType PowerMethod() override {
//do something
Base::PowerMethod();
}
If your problem is more complicated, and polymorphism and superclasses can't help you, you can always declare some method protected, so that only subclasses can access it. So, you could for example do this:
class Calc : public Base {
protected:
SomeType target;
void Simple() { target = 1; };
void Complex(){ target = 10000; };
public:
explicit Calc(bool isSimple) {
if(isSimple)
Simple();
else
Complex();
}
};
class SimpleCalc : public Calc {
public:
SomeType PowerMethod() override {
Calc::Simple();
return Calc::target;
};
};
class ComplexCalc : public Calc {
public:
SomeType PowerMethod() override {
Calc::Complex();
return Calc::target;
};
};
If your target is to learn OOP then you can use a factory design pattern to create your final calculator based on isSimple condition:
#include <iostream>
class Base
{
public:
Base()
{
target = 0;
}
int target;
virtual void PowerMethod() = 0;
};
class SimpleCalc : public Base
{
virtual void PowerMethod() { target = 0; }
};
class ComplexCalc : public Base
{
virtual void PowerMethod() { target = 1000; }
};
class CalcFactory
{
public:
virtual Base* createCalc(bool isSimple)
{
if (isSimple)
return new SimpleCalc();
else
return new ComplexCalc();
}
};
int main()
{
CalcFactory factory;
Base * base1 = factory.createCalc(true);
Base * base2 = factory.createCalc(false);
base1->PowerMethod();
base2->PowerMethod();
std::cout << base1->target << std::endl;
std::cout << base2->target << std::endl;
}
I want to make an abstract class, A that will be subclassed by Class B and Class C such that they will all use the same methods in the defined abstract class (B and C are A-able classes).
I have another class, Z, that will contain an array of A-able classes. I would like for it to have a function that allows it to swap between B and C in that array (ie. calling initializer/member function with an argument).
The below example, while not being exactly like what I'm describing above (not using abstract classes), showcases the same issue I'm running into: I'm unable to set the array to the correct subclass, since it's complaining that it was initialized as the parent class.
However, this should be possible to do right? What am I missing here?
#include <iostream>
#include <array>
class BaseItem {
protected:
std::string name;
BaseItem(const std::string & name) : name(name) {};
virtual void printName();
virtual ~BaseItem() = default;
};
class Item1: public BaseItem {
public:
using BaseItem::name;
Item1() : BaseItem("Book1") {}
void printName() {
std::cout << "1" << name;
}
};
class Item2: public BaseItem {
public:
using BaseItem::name;
Item2() : BaseItem("Book2") {}
void printName() {
std::cout << "2" << name;
}
};
class Library {
public:
std::array<BaseItem, 2> books;
void setToItem2() {
for (size_t i = 0; i < books.size(); i++) {
books[i] = new Item2();
}
}
void setToItem1() {
for (size_t i = 0; i < books.size(); i++) {
books[i] = new Item1();
}
}
void printBooks() {
for (auto& entry: books) {
entry->printName();
}
}
};
int main() {
Library a;
a.setToItem1();
a.printBooks();
a.setToItem2();
a.printBooks();
return 0;
}
Edit: Cleaned up a bit, also adding error message below:
prog.cpp: In member function ‘void Library::setToItem2()’:
prog.cpp:36:31: error: no match for ‘operator=’ (operand types are ‘std::array<BaseItem, 2>::value_type’ {aka ‘BaseItem’} and ‘Item2*’)
Edit2: Made the example code more representative of what I want to implement, utilizing code help from some of the existing answers.
Current potential solutions:
Evict books and pass in the correct subclass. This is currently what I'm going with. Just don't know if there is anything that can make this look cleaner (ie. all the casting looks a bit messy).
Make books a variant. The code looks cleaner here, but if I'm to extend to Item3, Item4, etc. I'll have to increase the variant to include all those subtypes, which IMHO defeats part of the purpose of making this "interface" (of course, we still get to inherit some shared things, but I'd like to not have to keep adding new classes into variant).
For now, I'm going to just do 1. But please let me know if there is something better.
Like other comments, if you store a vector of superclass by value, say vector<A>, as the vector allocates the memory, in addition to other information that vector stores, it will allocate sizeof(A)*NumOfElement(vector<A>) for storage. As subclasses, say B need more space than A, object slicing will occur. My suggestion is, instead of storing the class as value, store those as reference. ex)vector<shared_ptr<A>>. As the size of the pointer is same, this will allow to store A's subclasses. Oh, do not forget to define its virtual destructor!
Suggested code:
#include <iostream>
#include <vector>
#include <memory>
class Item {
public:
Item() : name("Book1") {}
std::string name;
virtual void f1() {/* Your Implementation here or make it pure virtual */};
virtual ~Item() = 0;
};
class Item2 : public Item {
public:
Item2() { name = "Book2"; }
//std::string name; //Hides base class name
void f1() override {/* Your Implementation here */};
~Item2() = default;
};
class Library {
public:
std::vector<std::shared_ptr<Item>> books;
void setToItem2() {
books.emplace_back(std::dynamic_pointer_cast<Item>(std::shared_ptr<Item2>(new Item2()))); //If you wish, use loop here
books.emplace_back(std::dynamic_pointer_cast<Item>(std::shared_ptr<Item2>(new Item2())));
}
void printBooks() {
for (auto& entry : books) {
std::cout << entry->name;
}
}
};
int main() {
Library a;
a.printBooks();
return 0;
}
The blessed way to store polymorphic instances in a container is to use std::unique_ptr. The container is still the sole owner of the object, but that pattern does not suffer the object slicing problem.
Furthermore your class hierarchy is weird: an Item2 instance will contain two versions of name. One (not directly accessible) in its Item base class and one directly accessible. It should at least be:
class Item2 : public Item {
public:
using Item::name;
Item2() {
name = "Book2";
}
};
But at construction time, name will first receive "Book1" at the base class initialization time, and then "Book2". So the normal way would be to build a base class like:
class BaseItem {
protected:
std::string name;
BaseItem(const std::string & name) : name(name) {};
virtual ~BaseItem() = default;
};
class Item: public BaseItem {
public:
using BaseItem::name;
Item() : BaseItem("Book1") {}
};
You can now build your Library class:
class Library {
public:
std::array<std::unique_ptr<BaseItem>, 2> books;
void printBooks() {
for (auto& entry : books) {
std::cout << entry->name;
}
}
};
Alternatively if you want to stick to a swapping pattern, you should use a variant:
class Library {
public:
std::variant<std::array<Item, 2>, std::array<Item2, 2> > books = std::array<Item, 2>();
void setToItem2() {
books = std::array<Item2, 2>();
}
void printBooks() {
auto *b = std::get_if< std::array<Item, 2> >(&books);
if (nullptr != b) {
for (auto& entry : *b) {
std::cout << entry.name << "\n";
}
}
else {
auto* b2 = std::get_if< std::array<Item2, 2> >(&books);
for (auto& entry : *b2) {
std::cout << entry.name << "\n";
}
}
}
};
int main() {
Library a;
a.printBooks();
a.setToItem2();
a.printBooks();
return 0;
}
I have six different classes that are all derived from an abstract base class named "Piece".
When looping through a vector of pointers to Piece as such:
std::vector<shared_ptr<Piece>>
Is there an efficient way to get the type of derived class that each pointer is pointing to?
Obviously I can just do something like this:
class Piece
{
public:
virtual std::string getType() = 0;
}
class Rook : public Piece
{
public:
std::string getType() override
{
return "Rook";
}
}
class Pawn : public Piece
{
public:
std::string getType() override
{
return "Pawn";
}
}
for (std::shared_ptr<Piece> p: std::vector<std::shared_ptr<Piece>>)
{
if (p->getType() == "Rook")
{
//Do something
}
else if(p->getType() == "Pawn")
{
//Do something else
}
}
But it seems like there would be a better way to do this?
Slightly more efficient would be an enum rather than a string, as these can be compared slightly faster (they're one integer!).
But it's ideal to try to avoid this need, if you can.
This:
if (p->getType() == "Rook")
{
//Do something
}
else if(p->getType() == "Pawn")
{
//Do something else
}
should just be this:
p->doThing();
… where doThing is a virtual function that does "the right thing" for whatever class it's implemented in.
Failing that, your pattern is not unusual.
As another answer shows, using an enum would be more efficient than using a string. But at the cost of having to maintain that enum if you ever decide to add more Piece-derived classes in the future (though, Chess only has a few distinct pieces, so I'm sure that will not happen).
Otherwise, have a look at dynamic_cast or std::dynamic_pointer_cast instead of a virtual method, eg:
class Piece
{
public:
virtual ~Piece() = default;
...
};
class Rook : public Piece
{
public:
...
void doSomething();
};
class Pawn : public Piece
{
public:
...
void doSomethingElse();
};
...
std::vector<std::shared_ptr<Piece>> pieces;
...
for (auto p : pieces)
{
if (Rook *rk = dynamic_cast<Rook*>(p.get()))
// or: if (auto rk = std::dynamic_pointer_cast<Rook>(p))
{
rk->doSomething();
}
if (Pawn *pn = dynamic_cast<Pawn*>(p.get()))
// or: if (auto pn = std::dynamic_pointer_cast<Pawn>(p))
{
pn->doSomethingElse();
}
}
But, as others have stated, this is not a good class design. This would be better handled by using a single virtual method for the actual work instead, eg:
class Piece
{
public:
virtual ~Piece() = default;
virtual void someAction() = 0;
...
};
class Rook : public Piece
{
public:
...
void someAction() override {
// do something ...
}
};
class Pawn : public Piece
{
public:
...
void someAction() override {
// do something else ...
}
};
...
std::vector<std::shared_ptr<Piece>> pieces;
...
for (auto p : pieces)
{
p->someAction();
}
Using enums and a function in base.
Untested concept code
enum class PieceType { Rock, Pawn, etc. };
class Piece {
enum id = -1; // no such piece
public:
virtual std::string getType() = 0;
enum PieceType GetId() {
return id;
}
}
class Rook : public Piece {
public:
Rock() : id(PieceType::Rock) {}
std::string getType() override {
return "Rook";
}
}
If it needs to be fast then this would do, if you just need to display it for one player once in a while, your method is fine.
Assuming that "Rook" and "Pawn" don't know about each other (like they are of different libraries) and that they also know nothing about your "Do something" code nor you have a vector of std::variant, it's not an easy task as you need to use some double-dispatch method.
The common solution is to create visitor interface per each derived class and visitor accept method.
So you have your Piece.cpp file:
struct Piece;
struct IPieceVisitor {
virtual void visit(Piece*) = 0;
};
struct Piece {
virtual void accept(IPieceVisitor *v) {
v->visit(this);
}
};
And Rook.cpp with all others implementing classes should have:
struct Rook;
struct IRookVisitor: public virtual IPieceVisitor {
virtual void visit(Rook*) = 0;
};
struct Rook : public Piece {
void accept(IPieceVisitor *v) override {
if(IRookVisitor *rv = dynamic_cast<IRookVisitor*>(v) {
return rv->visit(this);
}
Piece::accept(v); // consider that it may also be derived from some SpecialPiece
}
};
Now you can write your "Do something" visitor:
struct GratherKnownPiecesVisitor:
public IRookVisitor, public IPawnVisitor {
void visit(Rook* r) override{
m_knownPieces.push_back(r);
}
void visit(Pawn* p) override {
m_knownPieces.push_back(p);
}
void visit(Piece* p) override {
std::cerr << "Unknown piece!" << std::endl;
}
std::vector<std::variant<Rook*,Pawn*>> m_knownPieces;
};
Now you can smoothly run over the unknown container of base class pointers:
GratherKnownPiecesVisitor knownTypesVisitor;
for (std::shared_ptr<Piece> p: pieces) {
p->accept(&knownTypesVisitor);
}
The easier and perhaps faster solution is to use hash map indexed with type information:
std::unordered_map<std::type_index, std::functinon<void(Piece*)>>
But that way if someone create SpecialRook class, we cannot know that it is derived from our Rook class.
The fastest solution is to assign each object a value of your enum and then switch case to the type you want.
I am very new to c++ so I am trying to get a feeling of how to do things the right way in c++. I am having a class that uses one of two members. which one gets determined at instantiation. It looks something like
main() {
shared_pointer<A> a = make_shared<A>();
if ( checkSomething ) {
a->setB(make_shared<B>());
} else {
a->setC(make_shared<C>());
}
a->doStuff();
class A {
public:
doStuff() {
/*here I want to do something like call
m_b->doStuff() if this pointer is set and m_c->doStuff() if
that pointer is set.*/
}
setB( B* p ) { m_b = p; }
setC( C* p ) { m_c = p; }
B* m_b;
C* m_c;
}
}
B and C are some classes with doStuff() member function
There are many members like doStuff. Ideally I would avoid checking for nullptr in each of them. What is the best/most efficient/fastest way to create a switch between those two members?
Is there a way to use a static pointer so that I have a member
static **int m_switch;
and do something like
m_switch = condition ? &m_b : &m_c;
and call
*m_switch->doStuff();
Does the compiler here also replace the extra pointer hop because it is a static?
Is there any other smart way to do those switches?
Normally, class A would be an interface class, which both B and C would inherit and implement. But it sounds like you cannot do this for whatever reason.
Since you want to emulate this, you can start by making the interface:
class A_interface
{
public:
virtual void doStuff() = 0;
virtual void doThings() = 0;
virtual void doBeDoBeDo() = 0;
};
And then you make a template wrapper:
template< class T >
class A : public A_interface
{
public:
void doStuff() override { target.doStuff(); }
void doThings() override { target.doThings(); }
void doBeDoBeDo() override { target.doBeDoBeDo(); }
private:
T target;
};
This essentially does half of what your own example class A was trying to do, but now you can use a common interface. All you need to do is construct the correct templated version you want:
std::shared_ptr<A_interface> a;
if( checkSomething ) {
a = std::make_shared<A<B>>();
} else {
a = std::make_shared<A<C>>();
}
a->doStuff();
You need to have both members implement a common interface to use them similarly. But in order to do that, you need to define the interface and relay the calls to the B and C classes.
// existing classes
class B
{
public:
void doStuff() { std::cout << "B"; }
};
class C
{
public:
void doStuff() { std::cout << "C"; }
};
// define your interface
class I
{
public:
virtual void doStuff() = 0;
};
// new classes
class D : public B, public I
{
public:
void doStuff() override { B::doStuff(); }
};
class E : public C, public I
{
public:
void doStuff() override { C::doStuff(); }
};
// your A class
class A
{
public:
D* b = nullptr; // now type D
E* c = nullptr; // now type E
// your toggle
I* getActive()
{
if (b)
return b;
else
return c;
}
// simple doStuff() function
void doStuff()
{
getActive()->doStuff();
}
};
int main()
{
A a;
if (true)
a.b = new D; // need to initialize as D
else
a.c = new E; // need to initialize as E
a.doStuff(); // prints B
}
But typing this up made me realize that defining D and E could get really tiresome and against what you're trying to save. However, you can define a template to create them like #paddy has done.
There's no one-size-fits-all solution for your problem. What to use depends on your particular problem. A few possible answers:
Interfaces
Strategy Pattern
Pointers (to hold a function or class which implements doStuff)
An interface is like a contract. Any class which inherits from the interface must implement its members. For instance,
class IDoesStuff
{
public:
virtual ~IDoesStuff() {};
virtual void DoStuff() = 0;
};
Can now be used by other classes:
class Foo : public IDoesStuff
{
public:
virtual void DoStuff()
{
// ....
}
};
class Bar : public IDoesStuff
{
public:
virtual void DoStuff()
{
// ....
}
};
And now, in general, one may do:
Foo foo;
IDoesStuff *stuffDoer= &foo;
stuffDoer->doStuff();
This can be used in your particular use case as follows:
class A
{
IDoesStuff *stuffDoer; // Initialize this at some point.
public:
void doStuff() { stuffDoer->doStuff(); }
};
First you must change your memebr variables m_b and m_c to std::shared_ptr.
Add a member variable of type std::function(void()) to hold the target function you want to call. In your sample it is do_stuf.
In your setter functions you can bind target function to your std::function and in do_stuf just call std::function.
(You need a C++11 compiler)
class B
{
public:
void doStuff()
{
}
};
class C
{
public:
void doStuff()
{
}
};
class A
{
public:
void doStuff()
{
m_target_function();
}
void setB(std::shared_ptr<B> p)
{
m_b = p;
m_target_function = std::bind(&B::doStuff, m_b.get());
}
void setC(std::shared_ptr<C> p)
{
m_c = p;
m_target_function = std::bind(&C::doStuff, m_c.get());
}
std::shared_ptr<B> m_b;
std::shared_ptr<C> m_c;
std::function<void()> m_target_function;
};
int _tmain(int argc, _TCHAR* argv[])
{
std::shared_ptr<A> a = std::make_shared<A>();
bool use_B = false;
if (use_B)
{
a->setB(std::make_shared<B>());
}
else
{
a->setC(std::make_shared<C>());
}
a->doStuff();
}
I want to achieve such an outcome using c++:
Java:
public interface ITemp {
void onCall(double value);
}
In main:
double d=2;
ITemp mVariable = new ITemp() {
#Override
public void onCall(double value) {
... what to do... you can use 'd' variable...
}
};
In C++:
class ITemp {
public:
virtual void onCall(double something) =0;
virtual ~ITemp();
};
In main:
double d=2;
ITemp mVariable = .... // I cannot instantiate class containing pure virtual method
// But I want to use variable d to create a method
You can't do exactly that since you can't create anonymous classes in C++, but you can do something similar:
int main()
{
double d = 2;
class T : public ITemp
{
double& m_v;
public:
T(double& v) : m_v(v) {}
void onCall(double value)
{
// Do something with m_v;
m_v *= value;
}
} t(d);
t.onCall(4);
std::cout << "d: " << d << std::endl; // d is 8.
}
The reference ('&') makes m_v the same variable as d, but under a different name.
What about constructing class with d in constructor?
class ITemp {
double m_d;
public:
ITemp(double d) : m_d(d) {}
virtual void onCall(double something) = 0; // inside, you can use m_d variable along with something for whatever you want.
virtual ~ITemp();
};
I think i do not understand what is done in onCall method and how you want to use it. If you want to work with d, pass it to constructor or pass it to onCall as another parameter.
Of course, if that is not what you are trying to do, templates would help you. They are usually used to send different types into class each time however. It seems you do not need that.
You can implement the interface as an unnamed class, but you cannot access local variables and create a closure.
int main(int argc, char* argv[])
{
class : public ITemp
{
public:
virtual void onCall(double something)
{
std::cout << something;
}
} temp;
ITemp& itemp = temp;
itemp.onCall(100.3145);
return 0;
}