找到对象类型后,是否可以使用static_cast来投射对象?
After finding the object type, can I use static_cast to cast the object?
我已经编写了一个函数来确定传递哪个 class 对象,使用 dynamic_casting。
在条件中,我可以使用 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));
}
是static_cast
可以。另一方面,C++11 允许您编写
if(auto d1 = dynamic_cast<Derived1*>(bp)) {
d1-> func1();
} ...
所以没有必要两者兼而有之。
另一种选择是使用 C++17 std::variant
(或已经在 Boost 中的等效项)并避免 if-elseif-elseif 级联,就像它们在 cppreference 上显示的那样:
std::variant<Derived1*, Derived2*> p = new Derived1();
...
std::visit(overloaded(
[](Derived1* p) { p->func1(); },
[](Derived2* p) { p->func2(); }
), p);
如果您不能使用通用界面,这是最好的选择。但是请注意,如果某些代码像这样 'type-checking' 在对象上调用不同的函数,您可能在设计中遗漏了一些东西。
是可以,但有些情况下(涉及多重继承和虚拟基)可以动态转换,但不能静态转换。
不过,这些都无关紧要。有一种更简单的方法可以做你想做的事,只需在 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;
}
注意:d1
和d2
是指向可变对象的常量指针。鉴于我们从不修改它们,我想向编译器保证我们从不修改它们。这样编译器就可以更容易地推理它们进行优化,我也可以更容易地推理它们,当我三个月的时间来阅读代码时。
您可以在此处使用 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;
}
作为替代方案,您可以使用访问者模式:
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);
}
}
我已经编写了一个函数来确定传递哪个 class 对象,使用 dynamic_casting。 在条件中,我可以使用 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));
}
是static_cast
可以。另一方面,C++11 允许您编写
if(auto d1 = dynamic_cast<Derived1*>(bp)) {
d1-> func1();
} ...
所以没有必要两者兼而有之。
另一种选择是使用 C++17 std::variant
(或已经在 Boost 中的等效项)并避免 if-elseif-elseif 级联,就像它们在 cppreference 上显示的那样:
std::variant<Derived1*, Derived2*> p = new Derived1();
...
std::visit(overloaded(
[](Derived1* p) { p->func1(); },
[](Derived2* p) { p->func2(); }
), p);
如果您不能使用通用界面,这是最好的选择。但是请注意,如果某些代码像这样 'type-checking' 在对象上调用不同的函数,您可能在设计中遗漏了一些东西。
是可以,但有些情况下(涉及多重继承和虚拟基)可以动态转换,但不能静态转换。
不过,这些都无关紧要。有一种更简单的方法可以做你想做的事,只需在 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;
}
注意:d1
和d2
是指向可变对象的常量指针。鉴于我们从不修改它们,我想向编译器保证我们从不修改它们。这样编译器就可以更容易地推理它们进行优化,我也可以更容易地推理它们,当我三个月的时间来阅读代码时。
您可以在此处使用 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;
}
作为替代方案,您可以使用访问者模式:
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);
}
}