一、概述
static_pointer_cast从表面上看就是静态指针类型转换。细细看来,并不是那么简单,有一个隐形的限制条件。首先这个是c++11里的,更老的编译器不支持,其次指针是shared_ptr类型的,对于普通指针是无效的。还有一般只用在子类父类的继承关系中,当子类中要获取父类中的一些属性时,或工厂模式等需要通过父类参数接收不同子类实例的场景(当然了子类通过多态拥有自己的父类继承来的属性和行为,但是还想知道父类相应的属性和行为,这时,将父类的shared_ptr通过static_pointer_cast转化为子类的shared_ptr,这样就可以使得子类可以访问到父类的方法)。
这个函数返回的是shared_ptr类型sp的一份共享拷贝,只不过它指向的对象类型从原来的U变为T。
定义:
template <class T, class U>
shared_ptr<T> static_pointer_cast (const shared_ptr<U>& sp) noexcept;
解释:
Returns a copy of sp of the proper type with its stored pointer casted statically from U* to T*.
If sp is not empty, the returned object shares ownership over sp‘s resources, increasing by one the use count.
If sp is empty, the returned object is an empty shared_ptr.
二、实测
1.例1
// static_pointer_cast example
#include <iostream>
#include <memory>
struct A {
static const char* static_type;
const char* dynamic_type;
A() { dynamic_type = static_type; }
};
struct B: A {
static const char* static_type;
B() { dynamic_type = static_type; }
};
const char* A::static_type = "class A";
const char* B::static_type = "class B";
int main () {
std::shared_ptr<A> foo;
std::shared_ptr<B> bar;
foo = std::make_shared<A>();
// cast of potentially incomplete object, but ok as a static cast:
bar = std::static_pointer_cast<B>(foo);
std::cout << "foo's static type: " << foo->static_type << '\n';
std::cout << "foo's dynamic type: " << foo->dynamic_type << '\n';
std::cout << "bar's static type: " << bar->static_type << '\n';
std::cout << "bar's dynamic type: " << bar->dynamic_type << '\n';
return 0;
}
结果:
foo's static type: class A
foo's dynamic type: class A
bar's static type: class B
bar's dynamic type: class A
不用std::static_pointer_cast
// static_pointer_cast example
#include <iostream>
#include <memory>
struct A {
static const char* static_type;
const char* dynamic_type;
A() { dynamic_type = static_type; }
};
struct B: A {
static const char* static_type;
B() { dynamic_type = static_type; }
};
const char* A::static_type = "class A";
const char* B::static_type = "class B";
int main () {
std::shared_ptr<A> foo;
std::shared_ptr<B> bar;
foo = std::make_shared<A>();
// cast of potentially incomplete object, but ok as a static cast:
bar = std::make_shared<B>();
//bar = std::static_pointer_cast<B>(foo);
std::cout << "foo's static type: " << foo->static_type << '\n';
std::cout << "foo's dynamic type: " << foo->dynamic_type << '\n';
std::cout << "bar's static type: " << bar->static_type << '\n';
std::cout << "bar's dynamic type: " << bar->dynamic_type << '\n';
return 0;
}
结果
foo's static type: class A
foo's dynamic type: class A
bar's static type: class B
bar's dynamic type: class B
事实上,当在调用下面这句话时,B对象没有被构造(分配内存),bar是指向foo对象的。
// static_pointer_cast example
#include <iostream>
#include <memory>
struct A {
static const char* static_type;
const char* dynamic_type;
A() { std::cout << "construct A " << std::endl; dynamic_type = static_type; }
};
struct B: A {
static const char* static_type;
B() { std::cout << "construct B " << std::endl; dynamic_type = static_type; }
};
const char* A::static_type = "class A";
const char* B::static_type = "class B";
int main () {
std::shared_ptr<A> foo;
std::shared_ptr<B> bar;
std::cout << "foo's static type: " << foo->static_type << '\n';
std::cout << "bar's static type: " << bar->static_type << '\n';
foo = std::make_shared<A>();
// cast of potentially incomplete object, but ok as a static cast:
bar = std::static_pointer_cast<B>(foo);
std::cout << "foo's static type: " << foo->static_type << '\n';
std::cout << "foo's dynamic type: " << foo->dynamic_type << '\n';
std::cout << "bar's static type: " << bar->static_type << '\n';
std::cout << "bar's dynamic type: " << bar->dynamic_type << '\n';
return 0;
}
输出:
foo's static type: class A
bar's static type: class B
construct A
foo's static type: class A
foo's dynamic type: class A
bar's static type: class B
bar's dynamic type: class A
2.例2
再看以下转变过程
// static_pointer_cast example
#include <iostream>
#include <memory>
struct A {
static const char* static_type;
const char* dynamic_type;
A() { std::cout << "construct A " << std::endl; dynamic_type = static_type; }
};
struct B: A {
static const char* static_type;
B() { std::cout << "construct B " << std::endl; dynamic_type = static_type; }
};
const char* A::static_type = "class A";
const char* B::static_type = "class B";
int main () {
std::shared_ptr<A> foo;
std::shared_ptr<B> bar;
std::cout << "foo's static type: " << foo->static_type << '\n';
std::cout << "bar's static type: " << bar->static_type << '\n';
foo = std::make_shared<A>();
bar = std::make_shared<B>();
std::cout << "bar's static type: " << bar->static_type << '\n';
std::cout << "bar's dynamic type: " << bar->dynamic_type << '\n';
// cast of potentially incomplete object, but ok as a static cast:
bar = std::static_pointer_cast<B>(foo);
std::cout << "foo's static type: " << foo->static_type << '\n';
std::cout << "foo's dynamic type: " << foo->dynamic_type << '\n';
std::cout << "bar's static type: " << bar->static_type << '\n';
std::cout << "bar's dynamic type: " << bar->dynamic_type << '\n';
return 0;
}
输出
foo's static type: class A
bar's static type: class B
construct A #构造A
construct A #B继承A,构造B时先构造A
construct B
bar's static type: class B
bar's dynamic type: class B #B构造后它的dynamic type为class B
foo's static type: class A
foo's dynamic type: class A
bar's static type: class B
bar's dynamic type: class A #使用static_pointer_cast转换后dymamic type变为class A
三、结论
通过各种测试,基本可以看出来,static_pointer_cast可以将父类参数强制转换为子类类型,并继承子类的static属性。实际应用中,可以将方法参数定义为父类型,但实际传入子类型,通过static_pointer_cast获得子类特有的方法和static属性,类似下方的应用场景。
struct ContextTest : public ContextBase {
~ContextTest() {
PINFO << "[TaskFlow] Done! Context content is: " << content;
}
std::string content;
};
auto taskflow_ = std::make_shared<TaskFlow>(true);
auto taskA = taskflow->CreateSubTask([](std::shared_ptr<ContextBase>& c){
static int a_cnt = 0;
auto ctx = std::static_pointer_cast<ContextTest>(c); // 将ContextBase参数c强制转换为子类ContextTest类型,并继承ContextTest的static属性
ctx->content += "task A done in round " << std::to_string(a_cnt) << "; " ;
});
auto ctx = std::make_shared<ContextTest>();
ctx->content = "Round " + std::to_string(i) + " : ";
taskflow->Start(ctx);
22.6.28