I have 3 classes, A, B and C:
class A {
public:
virtual bool sm(B b) = 0;
virtual bool sm(C c) = 0;
};
class B : public A {
bool sm(B b) {
//code
}
bool sm(C c) {
//code
}
};
class C : public A {
bool sm(B b) {
//code
}
bool sm(C c) {
//code
}
};
And vector<A*> objects, that stores B or C objects. (for example they generates randomly)
Can I call somehow
for(int i = 0; i < objects.size(); i++) {
for(int j = i; j < objects.size(); j++) {
objects[i].sm(objects[j]);
}
}
Without dynamic cast or something? Because there can be a bit more of B-C classes
And is it a bag thing, and may be there is a better way to do it?
SOLUTION
As odelande said and I understood, this is the solution for my problem
#include <iostream>
#include <vector>
class B;
class C;
class A {
public:
virtual bool sm(A* a) = 0;
virtual bool sm(B* b) = 0;
virtual bool sm(C* c) = 0;
};
class B : public A {
public:
bool sm(A* a) {
return a->sm(this);
}
bool sm(B* b) {
std::cout << "In B doing B" << std::endl;
return true;
}
bool sm(C* c) {
std::cout << "In B doing C" << std::endl;
return false;
}
};
class C : public A {
public:
bool sm(A* a) {
return a->sm(this);
}
bool sm(B* b) {
std::cout << "In C doing B" << std::endl;
return true;
}
bool sm(C* c) {
std::cout << "In C doing C" << std::endl;
return false;
}
};
int main() {
std::vector<A*> objects;
objects.push_back(new B());
objects.push_back(new C());
objects[0]->sm(objects[0]);
objects[0]->sm(objects[1]);
objects[1]->sm(objects[0]);
objects[1]->sm(objects[1]);
std::cin.get();
return 0;
}
This code outputs
In B doing B
In C doing B
In B doing C
In C doing C
You cannot do it like this. The overloads of the sm() method are statically resolved, i.e. at compile time (besides, sm() should take pointers to B and C). But the compiler only knows that objects[j] is an A*; it cannot resolve the call because there is no overload that takes a A* as input.
What you want is to dispatch the call based on the runtime type of objects[j]. This is what a call to a virtual function does. So, you should only have one sm() method, which should in turn call another virtual method of its argument.
You're searching for the Visitor Pattern, multiple dispatch. The key is that you take a reference in sm(A& a) and call smT(...) on it. (Code is for example purposes only, will need clean-up and consts.)
class A {
protected:
virtual bool smB(B& b) = 0;
virtual bool smC(C& c) = 0;
public:
virtual bool sm(A& a) = 0;
};
class B : public A {
protected:
bool smB(B& b) {
// code,
}
bool smC(C& b) {
// code
}
public:
bool sm(A& a) {
a.smB( *this ); // this is smC(...) in class C
}
};
Related
I am working with conversion operators and I an error just popped out of nowhere. C class is derived from B and has no relation with class A, however, debugger shows that when doing C* val1 = new C val1 is showed as C* {A<B>}. It also produces an error because that A in the C* pointer has a size of an unreasonable size (it gives a different size each time it is executed so I just suppose it gets a number from another application).
#include <iostream>
#include <vector>
template<typename widget_type>
class A
{
public:
std::vector<widget_type*> value;
virtual ~A() {}
void Add(widget_type* val)
{
value.push_back(val);
}
template<typename return_type>
operator A<return_type>()
{
unsigned int size = this->value.size();
std::vector<return_type*> return_value;
return_value.reserve(size);
for (unsigned int i = 0; i < size; i++)
{
return_value[i] = dynamic_cast<return_type*>(this->value[i]);
}
A<return_type> target;
target.value = return_value;
return target;
}
};
class B
{
public:
virtual ~B() {}
};
class C : public B
{
public:
void Print()
{
std::cout << "C CALL\n";
}
};
class D : public B
{
};
int main()
{
std::cout << "Start!\n";
A<C> source;
C* val1 = new C;
source.Add(val1);
A<B> target = source;
A<B>* target2 = dynamic_cast<A<B>*>(&source);
std::cout << "END\n";
}```
for (unsigned int i = 0; i < size; i++)
{
return_value[i] = dynamic_cast<return_type*>(this->value[i]);
}
You are invoking undefined behaviour by accessing return_value[i] on an empty vector.
How can one access child class functions from a vector of a parent class without downcasting?
example:
class a {
public:
...
};
class b : public a {
double output() { // both child class have memeber function called output,
// but they return different data type.
return 0;
}
};
class c : public a {
bool output() { return false; }
};
// main
vector<a> vec;
b obj;
c obj2;
vec.push_back(obj);
vec.push_back(obj2);
for (int i = 0; i < vec.size(); i++) {
cout << vec[i].output();
}
Error:
error: no member function called "output" found in a
I have tried function overridding:
class a{
public:
auto output()
};
This approach don't work because I sometimes need to pass multiple parameters and this function doesn't allow that and will throw me the error: Function output expected 0 parameters, received x parameters.
It is possible like this
#include <iostream>
#include <vector>
struct result
{
enum
{
BOOL,
DOUBLE
} tag;
union ret {
double d;
bool b;
} r;
};
std::ostream &operator<<(std::ostream &s, const result &r)
{
switch (r.tag)
{
case result::DOUBLE:
s << r.r.d;
break;
case result::BOOL:
s << r.r.b;
break;
default:
break;
}
return s;
}
class a
{
public:
virtual result output() = 0;
};
class b : public a
{
result output() override
{
result r{result::DOUBLE, 132.};
return r;
}
};
class c : public a
{
result output() override
{
result r{result::BOOL, false};
return r;
}
};
int main(int argc, char const *argv[])
{
std::vector<a *> vec;
a *obj = new b;
a *obj2 = new c;
vec.push_back(obj);
vec.push_back(obj2);
for (int i = 0; i < vec.size(); i++)
{
std::cout << vec[i]->output() << std::endl;
}
return 0;
}
but its ugly. even more then
I'm looking to do something only if the class is a specific derived class. That is I have:
class X{
int id;
}
class A: public X{
void run();
}
class B: public X{
int lala;
}
And I want to do something along the line of:
main(){
vector<X *> types;
types.push_back(new A);
types.push_back(new B);
int var = 0;
for(int i = 0; i<types.size(); i++){
if(types[i].isType(A)) {types[i].run();}
}
for(int i = 0; i<types.size(); i++){
if(types[i].isType(B)) {var = lala;}
}
}
I do not want class B to have anything equivalent to run(), nor do I want class A to have an equivalent to lala.
I know fortran has a workaround with
select type ( x => var )
class is ( A )
x.run()
end select
But I wasn't sure what my options in C++ were.
Thanks
You are looking for dynamic_cast.
#include <vector>
using namespace std;
class X {
public:
int id;
virtual ~X() = default;
};
class A : public X {
public:
void run() {}
};
class B : public X {
public:
int lala;
};
main(){
vector<X *> types;
types.push_back(new A);
types.push_back(new B);
int var = 0;
for(int i = 0; i<types.size(); i++){
if (auto ta = dynamic_cast<A *>(types[i])) {
ta->run();
}
}
for(int i = 0; i<types.size(); i++){
if (auto tb = dynamic_cast<B *>(types[i])) {
var = tb->lala;
}
}
}
Also see it in action here: https://onlinegdb.com/B1d29P5if.
I had to fix a few other problems with the code. Since they are not a part of your question, I won't clarify here, but you are welcome to ask if something is not clear.
EDIT: The above solution has memory leaks, which I didn't fix, as it wasn't required by the question. For completeness, here is the main function with memory leaks fixed (https://onlinegdb.com/ByeOmu9iz):
int main() {
vector<unique_ptr<X>> types;
types.emplace_back(new A);
types.emplace_back(new B);
int var = 0;
for(int i = 0; i < types.size(); ++i) {
if (auto ta = dynamic_cast<A *>(types[i].get())) {
ta->run();
}
}
for(int i = 0; i < types.size(); ++i) {
if (auto tb = dynamic_cast<B *>(types[i].get())) {
var = tb->lala;
}
}
}
Note that this is a C++11 solution.
If you're working with an even older compiler, you'll have to keep using plain pointers as in the original solution, and deallocate the memory manually at the end by calling delete on each element of the vector. (And hope nothing throws an exception before you reach that step.)
You'll also have to replace auto ta with A* ta and auto tb with B* tb.
A modern C++17 solution to this problem is to use a vector of variants, i.e. std::vector<std::variant<A, B>>. You need a modern compiler for this.
Here is a complete example, based on the std::variant documentation:
#include <vector>
#include <variant>
#include <iostream>
class X {
int id;
};
class A: public X {
public:
void run() {
std::cout << "run\n"; // just for demonstration purposes
}
};
class B: public X {
public:
B(int lala) : lala(lala) {} // just for demonstration purposes
int lala;
};
int main() {
std::vector<std::variant<A, B>> types;
types.push_back(A()); // no more new!
types.push_back(B(123)); // no more new!
int var = 0;
for (auto&& type : types) {
std::visit([&](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, A>) {
arg.run();
} else {
var = arg.lala;
}
}, type);
}
std::cout << var << '\n'; // just for demonstration purposes
}
As a nice bonus, this solution elegantly gets rid of dynamic allocation (no more memory leaks, no smart pointers necessary).
I have two ideas....
Why not have a shared method that returns a value that gives context as to whether or not it is an A or B? If for example, lala is expected to return only values 0 or greater, you could have void run() instead be int run() and return -1 at all times.
class X {
int id;
virtual int run() = 0; //Assuming X isn't meant to be instantiated
}
class A: public X {
// Return -1 to differentiate between As and Bs
int run() { return -1; }
}
class B: public X {
int lala;
int run() { return lala;}
}
Then you have...
main(){
vector<X *> types;
types.push_back(new A);
types.push_back(new B);
int var = 0, temp = 0;
for( int i = 0; i<types.size(); i++ ) {
if( (temp = types[i].run()) != -1 )
var = temp;
....
}
}
Again, only works if lala would never expect to return a particular range of values.
You could also hide information in X, upon creation of an A or B to keep track of what you have.
class X {
int id;
bool isA;
}
class A: public X {
A() : isA(true) { };
void run();
}
class B: public X {
B() : isA(false) { } ;
int lala;
}
Then you have...
main(){
vector<X *> types;
types.push_back(new A);
types.push_back(new B);
int var = 0;
for( int i = 0; i<types.size(); i++ ) {
if( types[i].isA == true ) {
types[i].run();
}
else {
var = types[i].lala;
}
}
Naturally if you expect to add C, D, E, .... it will no longer be worth it, but for only two derived classes it isn't all that bad.
I would justify this based on the fact that users are already going to have to peer into the derived classes to see why they behave so differently for being derived from the same class. I would actually look into whether or not it makes sense for A and B to derive from X based on their interface.
I also wouldn't recommend dynamic_cast(ing) without informing someone that it's one of the more dangerous casts to perform and typically not recommended.
You could use dynamic_cast to check if the base class pointer is convertible to a derived instance.
Another option would be to have a virtual function that returns the typeinfo of the class and thus use that information to cast the pointer to a convertible type. Depending on how dynamic_cast is implemented this could be more performant. Thus, you could use this if you want to try and see whether or not this method is quicker on your platform.
As #Jarod42 noted, you would need to have a virtual function, destructor in this case, for dynamic_cast to work. In addition, you would simply need a virtual destrctor to avoid undefined behavior when deleting the instance.
Example
#include <iostream>
#include <string>
#include <vector>
#include <typeinfo>
struct A {
virtual ~A() {
}
virtual const std::type_info& getTypeInfo() const {
return typeid(A);
}
};
struct B : public A {
virtual const std::type_info& getTypeInfo() const override {
return typeid(B);
}
};
struct C : public A {
virtual const std::type_info& getTypeInfo() const override {
return typeid(C);
}
};
int main()
{
std::vector<A*> data;
data.push_back(new A);
data.push_back(new B);
data.push_back(new C);
for (auto& val : data) {
if (val->getTypeInfo() == typeid(A)) {
std::cout << "A";
}
else if (val->getTypeInfo() == typeid(B)) {
std::cout << "B";
}
else if (val->getTypeInfo() == typeid(C)) {
std::cout << "C";
}
std::cout << std::endl;
}
for (auto& val : data) {
delete val;
}
}
I am currently working on a small private project using C++ i came up with the following structure:
#include <iostream>
class A
{
std::vector<int> vec;
protected:
virtual bool onAdd(int toAdd) {
// should the 'adding' be suppressed?
// do some A specific checks
std::cout << "A::onAdd()" << std::endl;
return false;
}
public:
void add(int i) {
if(!onAdd(i)) {
// actual logic
vec.push_back(i);
}
}
};
class B : public A
{
protected:
bool onAdd(int toAdd) override {
// do some B specific checks
std::cout << "B::onAdd()" << std::endl;
return false;
}
};
In this example onAdd is basically meant to be a callback for add, but in a more polymorphic way.
The actual problem arises when a class C inherits from B and wants to override onAdd too. In this case the implementation in B will get discarded (i.e. not called) when calling C::add. So basically what I would like to achieve is a constructor-like behaviour where I am able to override the same method in different positions in the class hierarchy and all of those getting called.
My question now is: Is there a possibility/design to achieve this? I am sure that it wouldn't be as easy as cascading constructors, though.
Note: Don't focus too much on the add example. The question is about the callback like structure and not if it makes sense with an add.
I would just call my parents onAdd()
bool C::onAdd(int toAdd) {return my_answer && B::onAdd(toAdd);}
This can be a little confusing if you're expecting other developers to inherit from your base class. But for small private hierarchies it works perfectly.
I sometimes include a using statement to make this more explicit
class C : public B
{
using parent=B;
bool onAdd(int toAdd) override {return my_answer && parent::onAdd(toAdd);}
};
struct RunAndDiscard {
template<class Sig, class...Args>
void operator()(Sig*const* start, Sig*const* finish, Args&&...args)const{
if (start==finish) return;
for (auto* i = start; i != (finish-1); ++i) {
(*i)(args...);
}
(*(finish-1))(std::forward<Args>(args)...);
}
};
template<class Sig, class Combine=RunAndDiscard>
struct invokers {
std::vector<Sig*> targets;
template<class...Args>
decltype(auto) operator()(Args&&...args)const {
return Combine{}( targets.data(), targets.data()+targets.size(), std::forward<Args>(args)... );
}
};
struct AndTogetherResultWithShortCircuit {
template<class Sig, class...Args>
bool operator()(Sig*const* start, Sig*const* finish, Args&&...args)const{
if (start==finish) return true;
for (auto* i = start; i != (finish-1); ++i) {
if (!(*i)(args...)) return false;
}
return (*(finish-1))(std::forward<Args>(args)...);
}
};
This creates a per-instance table of things to do onAdd.
Creating a per-class table is harder; you need to chain your table with your parent type's table, which requires per-class boilerplate.
There is no way to get the C++ compiler to write either the per-instance version, or the per-class version, without doing it yourself.
There are C++20 proposals involving reflection and reification, plus the metaclass proposal, which may involve automating writing code like this (on both a per-instance and per-class basis).
Here is a live example of this technique being tested:
struct AndTogetherResultWithShortCircuit {
template<class Sig, class...Args>
bool operator()(Sig*const* start, Sig*const* finish, Args&&...args)const{
if (start==finish) return true;
for (auto* i = start; i != (finish-1); ++i) {
if (!(*i)(args...)) return false;
}
return (*(finish-1))(std::forward<Args>(args)...);
}
};
class A {
std::vector<int> vec;
protected:
invokers<bool(A*, int), AndTogetherResultWithShortCircuit> onAdd;
public:
void add(int i) {
if (!onAdd(this, i)) {
vec.push_back(i);
}
}
};
class B : public A
{
public:
B() {
onAdd.targets.push_back([](A* self, int x)->bool{
// do some B specific checks
std::cout << "B::onAdd(" << x << ")" << std::endl;
return x%2;
});
}
};
class C : public B
{
public:
C() {
onAdd.targets.push_back([](A* self, int x)->bool{
// do some B specific checks
std::cout << "C::onAdd(" << x << ")" << std::endl;
return false;
});
}
};
When you want to write your own OO-system, you can in C++, but C++ doesn't write it for you.
If you want a generic solution perhaps you could use CRTP with variadic templates instead of runtime polymophism.
Taking inspiration from this answer and this answer:
template<class... OnAdders> class A : private OnAdders... {
std::vector<int> vec;
template<class OnAdder>
bool onAdd(int toAdd){
return static_cast<OnAdder*>(this)->onAdd(toAdd);
}
template<typename FirstOnAdder, typename SecondOnAdder, class... RestOnAdders>
bool onAdd(int toAdd){
if (onAdd<FirstOnAdder>(toAdd))
return true;
return onAdd<SecondOnAdder, RestOnAdders...>(toAdd);
}
public:
void add(int i) {
if (onAdd<OnAdders...>(i))
return;
// actual logic
vec.push_back(i);
}
};
class B {
public:
bool onAdd(int toAdd) {
// do some B specific checks
std::cout << "B::onAdd()" << std::endl;
return false;
}
};
Which you could use like:
A<B,C> a;
a.add(42);
Live demo.
The following solution uses std::function to add each callback during each constructor:
#include <iostream>
#include <vector>
#include <functional>
class A
{
std::vector<int> vec;
protected:
bool onAdd(int toAdd)
{
// do some A specific checks
std::cout << "A::onAdd()" << std::endl;
return true;
}
// vector of callback functions. Initialized with A::onAdd() callback as the first entry
std::vector<std::function<bool(int)>> callbacks{{[this](int toAdd){return onAdd(toAdd); }}};
public:
void add(int i)
{
for(auto& callback : callbacks) {
if(!callback(i))
return;
}
// actual logic
vec.push_back(i);
}
};
class B : public A
{
public:
B()
{
callbacks.emplace_back([this](int toAdd){return onAdd(toAdd); });
}
protected:
bool onAdd(int toAdd)
{
// do some B specific checks
std::cout << "B::onAdd()" << std::endl;
return true;
}
};
class C : public B
{
public:
C()
{
callbacks.emplace_back([this](int toAdd){return onAdd(toAdd); });
}
protected:
bool onAdd(int toAdd)
{
// do some C specific checks
std::cout << "C::onAdd()" << std::endl;
// must also call B::onAdd()
return true;
}
};
int main()
{
C c;
c.add(5);
}
Prints:
A::onAdd()
B::onAdd()
C::onAdd()
Let's say we have the following scenario:
We have a base abstract class A. Then we have classes B and C which derived from A. We also have class D which is a custom implementation of a std::vector<T> - it contains a private property list of type std::vector<T> and some custom methods to work with it.
Now my problem is as follows: I would like to overload the operator + in class A to be able to do this:
B* b = new B();
C* c = new C();
D mList = b+c; //the property *list* of mList would contain b an c
I have tried everything and can't seem to be able to get it to work and am out of ideas. Is it even possible to override an operator in a base abstract class so that it will apply to derived classes?
EDIT:
Here is what I have tried so far:
File A.h:
#pragma once
#include <string>
#include <iostream>
using namespace std;
class A
{
protected:
double price;
string name;
public:
A() :name(""){};
A(string n, double p){
price = p;
name = n;
};
~A(){};
virtual void calculate(double value) = 0;
virtual void print() const = 0;
};
File B.h:
#pragma once
#include "A.h"
class B : public A
{
private:
public:
B() :A(){};
B(string n, double p) :A(n,p){};
~B();
void calculate(double value)
{
price = price + value;
}
void print() const
{
cout << name << " says: " << " " << price;
}
};
File C.h:
#include "A.h"
class C : public A
{
private:
public:
C() :A(){};
C(string n, double p) : A(n,p){};
~C();
void calculate(double value)
{
price = price * value;
}
void print() const
{
cout << name << " says: " << " " << price;
}
};
File D.H:
#include <vector>
class D
{
private:
vector<A*> list;
public:
D(){}
~D()
{
int len = list.size();
for (int i = 0; i < len; i++)
{
delete list[i];
}
};
void push(A* item)
{
list.push_back(item);
}
A* pop()
{
A* last = list.back();
list.pop_back();
return last;
}
//I have tried overriding it here and in A.h
friend D D::operator+(A* first, A* second)
{
D temp;
temp.push(first);
temp.push(second);
return temp;
}
};
It looks like you're are adding two pointers, so A::operator+() won't even be called. But to answer your question, yes, operator overloading is inheritable. Even from an abstract base class.
class A
{
public:
virtual void test() = 0;
int operator+(const A &a) {return 42;}
};
class B : public A
{
void test() {};
};
class C : public A
{
void test() {};
};
int main()
{
B* b = new B();
C* c = new C();
cout << "result: " << *b + *c << endl;
return 0;
}
Output:
result: 42
When c in C* and d is a D* if you write c+d you're just adding pointers, whatever overloads you defined.
Maybe you could redefine pointer addition for A* with a global operator(A*, A*) (not sure it's possible) but it would be quite dangerous for users since it overrides standard behavior.
The better solution is to define operators on references (const) and not pointers, which in your case is a little less convenient since you'd have to write: list = *c + *d;
Also, since you're using containers of pointers for polymorphism, I strongly recommend using shared_ptr.
Working code below (simplified, but with the ability to add more than 2 elements):
#include <list>
using std::list;
struct A {
list<const A*> operator+(const A& right) { // A + A
list<const A*> r;
r.push_back(this);
r.push_back(&right);
return r;
}
list<const A*> operator+(const list<const A*> & right) { // A + list
list<const A*> r = right;
r.push_front(this);
return r;
}
virtual void print() const = 0;
};
list<const A*> operator+(const list<const A*> & left, const A & right) { // list + A
list<const A*> r = left;
r.push_back(&right);
return r;
}
#include <iostream>
struct B : A {
void print() const { std::cout << "B" << std::endl; }
};
struct C : A {
void print() const { std::cout << "C" << std::endl; }
};
int main() {
B b;
C c;
B* pb = new B;
list<const A*> lst = b + c + *pb;
for(list<const A*>::iterator i = lst.begin(); i != lst.end(); ++i) {
(*i)->print();
}
return 0;
}
Take a look at this code-example:
#include <iostream>
class B;
class A;
class A
{
public:
virtual void overrideProp() = 0;
friend int operator+(const B& b, const A& a);
friend std::ostream& operator<<(std::ostream& os, const A& a)
{
return os << a.prop;
}
protected:
int prop;
};
class B : public A
{
public:
B(){overrideProp();}
void overrideProp(){prop=1;}
};
class C : public A
{
public:
C(){overrideProp();}
void overrideProp(){prop=3;}
};
int operator+(const B& b, const A& a)
{
return b.prop + a.prop;
}
class D
{
public:
void operator=(const int& i){d = i;}
friend std::ostream& operator<<(std::ostream& os, const D& a)
{
return os << a.d;
}
private:
int d;
};
int main()
{
B b;
C c;
D d; d = b+c;
std::cout << "B contains: " << b << " C contains: " << c << " D contains: " << d;
}
The output is B contains: 1 C contains: 3 D contains: 4
Here's an compilable and runnable example (http://codepad.org/cQU2VHMp) I wrote before you clarified the question, maybe it helps. The idea is that the addition overload can either be unary (and D defined as a friend), as here, or defined as a non-member binary operator using public methods. Note that I have to dereference the pointers b and c to make this work, as adding pointers often don't make sense.
#include <iostream>
#include <string>
class D {
public:
void Foo() {
std::cout << "D: " << member_ << std::endl;
}
friend class A;
private:
std::string member_;
};
class A {
public:
virtual void Foo() = 0;
A(const std::string &member) : member_(member) {}
D operator+(const A &rhs) {
D out;
out.member_ = member_ + " " + rhs.member_;
return out; // Uses the default copy constructor of D
}
protected:
std::string member_;
};
class B : public A {
public:
B(const std::string &member) : A(member) {}
void Foo() {
std::cout << "B: " << member_ << std::endl;
}
};
class C : public A {
public:
C(const std::string &member) : A(member) {}
void Foo() {
std::cout << "C: " << member_ << std::endl;
}
};
int main() {
B *b = new B("hello");
C *c = new C("world");
b->Foo();
c->Foo();
D d = (*b) + (*c);
d.Foo();
delete b;
delete c;
return 0;
}
The output of this program is:
B: hello
C: world
D: hello world