Reputation: 1064
I have written a function that determines which class object is passed, using dynamic_casting. Inside the condition, can I use static_cast to actually cast the object?
For example, inside someFunc()
class Base
{
public:
Base() { cout << "Base::Base" << endl; }
virtual ~Base() { cout << "Base::~Base" << endl; }
};
class Derived1 : public Base
{
public:
void func1() { cout << "Derived1::func1()" << endl; }
};
class Derived2 : public Base
{
public:
void func2() { cout << "Derived2::func2()" << endl; }
};
void someFunc(Base * bp)
{
if(dynamic_cast<Derived1 *>(bp))
{
Derived1 * d1 = static_cast<Derived1 *>(bp); // static_cast ok?
d1->func1();
}
else if(dynamic_cast<Derived2 *>(bp))
{
Derived2 * d2 = static_cast<Derived2 *>(bp); // static_cast ok?
d2->func2();
}
else
cout << "None" << endl;
}
int main()
{
Derived1 * derived1 = new Derived1;
Derived2 * derived2 = new Derived2;
vector<Base *> vb;
vb.push_back(derived1);
vb.push_back(derived2);
// ---- Passing to someFunc() ----
someFunc(vb.at(0));
someFunc(vb.at(1));
}
Upvotes: 2
Views: 1374
Reputation: 217255
As alternative, you might use visitor pattern:
class Base;
class Derived1;
class Derived2;
class IBaseVisitor
{
public:
virtual ~IBaseVisitor() = default;
virtual void visit(Base&) = 0;
virtual void visit(Derived1&) = 0;
virtual void visit(Derived2&) = 0;
};
Then your classes with the accept
method:
class Base
{
public:
Base() { std::cout << "Base::Base" << std::endl; }
virtual ~Base() { std::cout << "Base::~Base" << std::endl; }
virtual void accept(IBaseVisitor& v) { v.visit(*this); }
};
class Derived1 : public Base
{
public:
void func1() { std::cout << "Derived1::func1()" << std::endl; }
void accept(IBaseVisitor& v) override { v.visit(*this); }
};
class Derived2 : public Base
{
public:
void func2() { std::cout << "Derived2::func2()" << std::endl; }
void accept(IBaseVisitor& v) override { v.visit(*this); }
};
Then the usage:
struct SomeFuncVisitor : IBaseVisitor
{
void visit(Base&) override { std::cout << "None" << std::endl; }
void visit(Derived1& d1) override { d1.func1(); }
void visit(Derived2& d2) override { d2.func2(); }
};
int main()
{
Derived1 derived1;
Derived2 derived2;
std::vector<Base *> vb {&derived1, &derived2};
SomeFuncVisitor visitor;
for (Base* base : vb) {
base->accept(visitor);
}
}
Upvotes: 1
Reputation: 28987
It is OK, but there are some cases (involving multiple inheritance and virtual bases) where you can dynamic cast, but not static cast.
However, that is all irrelevant. There is a much simpler way of doing what you want, just declare and initialize the variable in the if
:
void someFunc(Base * bp)
{
if(const auto d1 = dynamic_cast<Derived1 *>(bp))
{
d1->func1();
}
else if(const auto d2 = dynamic_cast<Derived2 *>(bp))
{
d2->func2();
}
else
cout << "None" << endl;
}
Note: d1
and d2
are constant pointers to mutable objects. Given we never modify them, I like to promise the compiler that we never modify them. That way the compiler can more easily reason about them for optimization, and I can more easily reason about them when I come to read the code in three months time.
Upvotes: 4
Reputation: 21
You can use static_cast to cast here but you could also leverage the dynamic_cast result to do the same thing.
void someFunc(Base * bp)
{
if( Derived1 * d1 = dynamic_cast<Derived1 *>(bp))
{
d1->func1();
}
else if(Derived2 * d2 = dynamic_cast<Derived2 *>(bp))
{
d2->func2();
}
else
cout << "None" << endl;
}
Upvotes: 1
Reputation: 41509
Yes static_cast
is ok. On the other hand, C++11 lets you write
if(auto d1 = dynamic_cast<Derived1*>(bp)) {
d1-> func1();
} ...
so there is no need to have both.
Another option is to work with a C++17 std::variant
(or the equivalent which is in Boost already) and avoid the if-elseif-elseif cascade, like they show on cppreference:
std::variant<Derived1*, Derived2*> p = new Derived1();
...
std::visit(overloaded(
[](Derived1* p) { p->func1(); },
[](Derived2* p) { p->func2(); }
), p);
If you can't use the common interface, this is the best option. Note, however, that if certain code is 'type-checking' like this to call a different function on the object, you may have missed something in your design.
Upvotes: 2