找到对象类型后,我可以使用static_cast来转换对象吗?

时间:2017-11-03 08:16:01

标签: c++ dynamic-cast downcast static-cast

我编写了一个函数,使用 dynamic_cast 来确定传递哪个类对象。 在条件中,我可以使用 static_cast 来实际投射对象吗?

例如,在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));
}

4 个答案:

答案 0 :(得分:4)

确定,但是有些情况(涉及多个继承和虚拟基础)你可以动态转换,但不能静态转换。

然而,这一切都无关紧要。有一种更简单的方法可以做你想做的事情,只需在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;
}

注意:d1d2是可变对象的常量指针。鉴于我们从不修改它们,我想承诺编译器我们永远不会修改它们。这样编译器可以更容易地推理它们进行优化,当我在三个月内阅读代码时,我可以更容易地推断出它们。

答案 1 :(得分:2)

static_cast没问题。另一方面,C ++ 11允许你编写

if(auto d1 = dynamic_cast<Derived1*>(bp)) {
  d1-> func1();
} ...

所以没有必要同时拥有两者。

另一种选择是使用C ++ 17 std::variant(或已经在Boost中的等价物)并避免使用if-elseif-elseif级联,就像它们在cppreference上所示:< / p>

std::variant<Derived1*, Derived2*> p = new Derived1();
...
std::visit(overloaded(
  [](Derived1* p) { p->func1(); },
  [](Derived2* p) { p->func2(); }
), p);

如果您不能使用通用界面,这是最佳选择。但请注意,如果某些代码是“类型检查”,就像调用对象上的不同函数一样,您可能会错过设计中的某些内容。

答案 2 :(得分:1)

你可以在这里使用static_cast进行投射,但你也可以利用dynamic_cast结果做同样的事情。

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;
}

答案 3 :(得分:1)

作为替代方案,您可以使用访客模式:

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;
};

然后使用accept方法编写您的课程:

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); }
};

然后用法:

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);
    }
}

Demo