interface A
{
void f();
}
interface B
{
void f();
}
class C : A ,B
{
// pseudocode
void A::a(){}
void B::a(){}
}
Is there a way to have different implementations of A::f and B::f in the same class?
When they both have the same signature, no*. If A.f is void f() and B.f is int f(), it's possible.
* actually, there is a way, if you accept that it's not doing exactly the same thing:
interface A { string f(); }
interface B { string f(); }
class C : A {
string f() { return "A"; }
string bf() { return "B"; }
// Pretend to be a B
alias get this;
B get() {
auto that = this;
return new class B {
string f() { return that.bf(); }
};
}
}
unittest {
auto c = new C();
A a = c;
B b = c;
assert(a.f() == "A");
assert(b.f() == "B");
}
In the above code, we are using alias this to create a kind of second inheritance chain. There are some problems with this, the biggest that we can't cast from the thing returned from get() back to C.
This could be made more generic with UDAs and a mixin, such that this should compile and run:
interface A { string f(); }
interface B { string f(); }
interface C { string f(); }
#implements!(B, C)
class D : A {
string f() { return "A"; }
#implements!(B.f)
string bf() { return "B"; }
#implements!(C.f)
string cf() { return "C"; }
mixin implement!();
}
unittest {
D d = new D();
A a = d;
B b = d;
C c = d;
assert(a.f() == "A");
assert(b.f() == "B");
assert(c.f() == "C");
assert(a == cast(A)d);
assert(b == cast(B)d);
assert(c == cast(C)d);
}
That, however, is left as an exercise for the reader.
Related
I have an abstract struct I with method a. B and B2 will inherit from it. X struct has an I type member and will instantiate it via createInsance template method based on type. I want to have on B2 an additional function b2Exclusive but I got compilation error that it is not present in A.
error: ‘using element_type = struct B’ {aka ‘struct B’} has no member named ‘b2Exclusive’
Is any way for solving this without defining b2Exclusive for B as well and to keep to structure this way?
#include <iostream>
#include <memory>
using namespace std;
struct I
{
virtual void a() = 0;
};
struct B : public I
{
B()
{
std::cout<<"B\n";
}
void a()
{
std::cout<<"-a from B\n";
}
};
struct B2 : public I
{
B2()
{
std::cout<<"B2\n";
}
void a()
{
std::cout<<"-a from B2\n";
}
void b2Exclusive()
{
std::cout<<"-something for B2\n";
}
};
using Iptr = std::shared_ptr<I>;
struct X
{
void createI()
{
if (type == "B")
{
createInstance<B>();
}
else
{
createInstance<B2>();
}
}
template <typename T>
void createInstance()
{
auto i = std::make_shared<T>();
if (type == "B2")
{
i->b2Exclusive();
}
}
std::string type = "None";
};
int main()
{
X x;
x.type = "B2";
x.createI();
return 0;
}
You can only call b2Exclusive if the template function use typename B2: one way to do so is to create the specialization for that type, such as this for example:
struct X
{
void createI();
template <typename T>
void createInstance()
{
//do something
}
std::string type = "None";
};
template<>
void X::createInstance<B2> ()
{
auto i = std::make_shared<B2>();
i->b2Exclusive();
}
void X::createI()
{
if (type == "B")
{
createInstance<B>();
}
else
{
createInstance<B2>();
}
}
int main()
{
X x;
x.type = "B2";
x.createI();
return 0;
}
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 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
}
};
This question already has answers here:
Do distinct functions have distinct addresses?
(4 answers)
Closed 7 years ago.
is this a bug in VS 2013 compiler?
The following code produces different result in debug and release.
In debug the result is as expected, but in release it is "A"
#include <cstdio>
struct A
{
virtual void* getClass() { return A::ID; };
static void ID(){};
};
struct B : public A
{
virtual void* getClass() { return B::ID; };
static void ID(){};
};
struct C : public A
{
virtual void* getClass() { return C::ID; };
static void ID(){};
};
int main(int argc, char *argv[])
{
A* d = new C;
if (d->getClass() == A::ID)
{
printf("A");
}
else if (d->getClass() == B::ID)
{
printf("B");
}
else if (d->getClass() == C::ID)
{
printf("C");
}
}
It's due to compiler optimizations.
It appears that whether the compiler should perform this kind of optimization is debatable Do distinct functions have distinct addresses? .
typeid
A more conventional way is to use typeid to verify the runtime types. Note you dereference the pointer to get the type of the derived class.
if (typeid(*d) == typeid(A))
{
printf("A");
}
else if (typeid(*d) == typeid(B))
{
printf("B");
}
else if (typeid(*d) == typeid(C))
{
printf("C");
}
Disable Optimization
However, because /OPT:ICF can merge identical data or functions, it can change the function names that appear in stack traces.
You can use /OPT:NOICF in release to prevent the behavior.
Also, you can see that actually implementing the functions differently causes it to work as you expect.
Example Code
#include <string>
struct A
{
virtual std::string getClass() { return A::ID(); }
static std::string ID(){ return "A"; }
};
struct B : public A
{
virtual std::string getClass() { return B::ID(); }
static std::string ID(){ return "B"; }
};
struct C : public A
{
virtual std::string getClass() { return C::ID(); }
static std::string ID(){ return "C"; }
};
int main(int argc, char *argv[])
{
A* d = new C;
if (d->getClass() == A::ID())
{
printf("A");
}
else if (d->getClass() == B::ID())
{
printf("B");
}
else if (d->getClass() == C::ID())
{
printf("C");
}
}
What is the best way to represent one-to-one object association in C++? It should be as automatic and transparent as possible meaning, that when one end is set or reset, the other end will be updated. Probably a pointer-like interface would be ideal:
template<typename AssociatedType>
class OneToOne{
void Associate(AssociatedType &);
AssociatedType &operator* ();
AssociatedType *operator->();
}
Is there any better way to do it or is there any complete implementation?
EDIT:
Desired behavior:
struct A{
void Associate(struct B &);
B &GetAssociated();
};
struct B{
void Associate(A &);
A &GetAssociated();
};
A a, a2;
B b;
a.Associate(b);
// now b.GetAssociated() should return reference to a
b.Associate(a2);
// now b.GetAssociated() should return reference to a2 and
// a2.GetAssociated() should return reference to b
// a.GetAssociated() should signal an error
Untested, but you could use a simple decorator
template <typename A1, typename A2>
class Association
{
public:
void associate(A2& ref)
{
if (_ref && &(*_ref) == &ref) return; // no need to do anything
// update the references
if (_ref) _ref->reset_association();
// save this side
_ref = ref;
ref.associate(static_cast<A1&>(*this));
}
void reset_association() { _ref = boost::none_t(); }
boost::optional<A2&> get_association() { return _ref; }
private:
boost::optional<A2&> _ref;
};
now:
struct B;
struct A : public Association<A, B> {
};
struct B : public Association<B, A> {
};
now these operations should be handled correctly.
A a, a2;
B b;
a.associate(b);
b.associate(a2);
NOTES: I use boost::optional to hold a reference rather than pointer, there is nothing stopping you from using pointers directly. The construct you are after I don't think exists by default in C++, which is why you need something like the above to get it to work...
Here is one class that can represent a bi-directional one-to-one relation:
template <class A, class B>
class OneToOne {
OneToOne<A,B>* a;
OneToOne<A,B>* b;
protected:
OneToOne(A* self) : a(self), b(0) {}
OneToOne(B* self) : a(0), b(self) {}
public:
void associateWith(OneToOne<A,B>& other) {
breakAssociation();
other.breakAssociation();
if (a == this) {
if (b != &other) {
breakAssociation();
other.associateWith(*this);
b = &other;
}
}
else if (b == this) {
if (a != &other) {
breakAssociation();
other.associateWith(*this);
a = &other;
}
}
}
A* getAssociatedObject(B* self) { return static_cast<A*>(a); }
B* getAssociatedObject(A* self) { return static_cast<B*>(b); }
void breakAssociation() {
if (a == this) {
if (b != 0) {
OneToOne<A,B>* temp = b;
b = 0;
temp->breakAssociation();
}
}
else if (b == this) {
if (a != 0) {
OneToOne<A,B>* temp = a;
a = 0;
temp->breakAssociation();
}
}
}
private:
OneToOne(const OneToOne&); // =delete;
OneToOne& operator=(const OneToOne&); // =delete;
};
Perhaps check out boost::bimap, a bidirectional maps library for C++.