如果我创建一个指向基类的成员,我通常可以将它转换为指向派生的成员,但是在下面的Buzz模板中使用时,第一个模板参数会影响第二个模板参数.我是在与编译器错误斗争还是标准真的要求这不起作用?
struct Foo
{
int x;
};
struct Bar : public Foo
{
};
template<class T, int T::* z>
struct Buzz
{
};
static int Bar::* const workaround = &Foo::x;
int main()
{
// This works. Downcasting of pointer to members in general is fine.
int Bar::* y = &Foo::x;
// But this doesn't, at least in G++ 4.2 or Sun C++ 5.9. Why not?
// Error: could not convert template argument '&Foo::x' to 'int Bar::*'
Buzz<Bar, &Foo::x> test;
// …Run Code Online (Sandbox Code Playgroud) 我正在开发一个实现专有协议的服务器项目。服务器是用C++实现的工厂模式,我们现在面临着向下转型的问题。
我正在研究的协议是为自动控制慢速网络而设计的,例如RS485、ZigBee、窄带PLC 等。我们设计了工厂模式的主服务器。当接收到新帧时,我们首先识别该帧的关联设备类型,调用工厂方法生成新的“解析器”实例,并将帧分派给解析器实例。
我们的专有协议是纯二进制实现的,我们可能需要的每一个信息都记录在帧本身中,因此可以尽可能简单地定义基本接口。我们还将为我们的工厂实现自动注册方法(此处省略了与 std::map 操作相关的详细代码):
// This is our "interface" base-class
class parser
{
public:
virtual int parse(unsigned char *) = 0;
virtual ~parser() { }
};
// The next two classes are used for factory pattern
class instance_generator
{
public:
virtual parser *generate() = 0;
};
class parser_factory
{
private:
static std::map<int,instance_generator*> classDB;
public:
static void add(int id, instance_generator &genrator);
parser *get_instance(int id);
};
// the two template classes are implementations of "auto-regisrtation"
template <class G, int ID> …Run Code Online (Sandbox Code Playgroud) 鉴于以下代码:
class Animal
{ }
class Dog : Animal
{ }
class Cage<T>
{
private T animal;
public Cage(T animal)
{
this.animal = animal;
}
public T Animal
{
get { return animal;}
}
}
class Program
{
static void Main(string[] args)
{
Dog dog = new Dog();
Cage<Animal> animalCage = new Cage<Animal>(dog);
Cage<Dog> dogCage = (Cage<Dog>)animalCage;
}
}
Run Code Online (Sandbox Code Playgroud)
如何解决最后一个编译器错误(从animalCage转换为dogCage)?
在我的代码中我知道笼子里有一只狗,但是我找不到一种方法来施放它.我是创建转换器并从Cage <Animal>的值创建新的Cage <Dog>实例的唯一替代方法吗?
如何让它发挥作用?之前的错误/注释行return 0;
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class Base
{
public:
void foobar() { cout << "foobar"; }
};
class Derived : public Base
{
public:
void print() { cout << "hello world!"; }
};
int main(int argc, char *argv[])
{
vector<unique_ptr<Base>> bases;
bases.push_back(unique_ptr<Base> (new Derived()));
//ok
bases[0]->foobar();
//error
//how can I make this works?
static_cast<Derived*> (bases[0])->print();
return 0;
}
Run Code Online (Sandbox Code Playgroud) 当没有涉及虚函数时,有没有办法从虚拟基类转发到派生类?这里有一些代码来演示我在说什么:
struct Base1
{
int data;
};
struct Base2
{
char odd_size[9];
};
struct ViBase
{
double value;
};
struct MostDerived : Base1, Base2, virtual ViBase
{
bool ok;
};
void foo(ViBase &v)
{
MostDerived &md = somehow_cast<MostDerived&>(v); //but HOW?
md.ok = true;
}
int main()
{
MostDerived md;
foo(md);
}
Run Code Online (Sandbox Code Playgroud)
请注意,该代码仅用于演示.我的真实场景相当复杂,涉及模板参数和从一个到另一个的转换,只知道第一个是第二个的基础; 它可以是普通或虚拟的基础,它可能有也可能没有虚函数.(参见底部的简化示例).我可以使用类型特征检测多态情况和虚拟/非虚拟基本情况,并解决除非多态虚拟基础之外的所有情况.这就是我要问的问题.
我真的想不出一种做演员的方法:
隐含的转换是正确的; 这些只做了预告.
static_cast 明确禁止从虚拟基类进行转换:
5.2.9/2 ...并且
B既不是虚拟基类,D也不是虚基类的基类D....
dynamic_cast 也不能这样做,因为downcast需要一个多态类
5.2.7/6否则,
v应该是指向多态类型的指针或glvalue(10.3).10.3/1 ...声明或继承虚函数的类称为多态类.
reinterpret_cast 在这里根本不适用.
如果 …
这是一个显然不起作用的代码,因为在构造函数中向下转换“this”是非法的:
#include <cassert>
class A {
protected:
virtual ~A() {}
public:
A();
};
class B : public A {
};
A::A() {
assert(dynamic_cast<B*>(this));
}
int main(void) {
B b;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,当用 g++ 编译时,断言失败。
然而,这是另一个有效的代码(至少在 g++ 4.7 中,我没有尝试过其他编译器):
#include <cassert>
class A {
protected:
virtual ~A() {}
public:
A() {}
void f();
};
class B : public A {
public:
B() {
f();
}
};
void A::f() {
assert(dynamic_cast<B*>(this));
}
int main(void) {
B b;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:第二个代码是否“合法”,即我可以期望任何编译器都能以这种方式工作吗? …
我想知道c ++是否保证将祖母基类降级为盛大的子类,就像奇怪的重复模板模式一样.以下代码在我的环境中运行良好.但是我不确定它是否适用于任何条件/环境.请告诉我你的了解.非常感谢你.
PS.老实说,我不确定我的方式要求堆栈溢出是好还是坏.如果您发现了坏点,请告诉我.再次感谢你.
#include <iostream>
template <typename GrandChild>
class GrandBase {
public:
void print(void) {
const GrandChild* grand_child = static_cast<const GrandChild*>(this);
std::cout << "GrandChild::value = " << grand_child->grand_child_value << std::endl;
}
};
template <typename Derived>
class BridgeClass : public GrandBase<Derived> {};
class GrandChild : public BridgeClass<GrandChild> {
public:
GrandChild() = default;
virtual ~GrandChild() = default;
int grand_child_value = 17;
};
void test_down_casting_to_grand_base(void) {
GrandChild a;
a.print();
}
int main(int argc, char **argv) {
test_down_casting_to_grand_base();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是
GrandChild::value = …Run Code Online (Sandbox Code Playgroud) 在 C++ 中,没有使我的析构函数成为 virtual是否仍然可以向下转换我的非多态基类的指针/引用?
我有以下结构:
#[derive(Debug)]
pub struct Entry {
pub index: usize,
pub name: String,
pub filename_offset: u64,
pub entry_type: EntryType,
}
#[derive(Debug)]
pub enum EntryType {
File {
file_offset: u64,
length: usize,
},
Directory {
parent_index: usize,
next_index: usize,
},
}
Run Code Online (Sandbox Code Playgroud)
Entry是GameCube ROM文件系统表中的一个条目,它描述了一个文件或目录.我定义了各种方法,Entry如Entry::read_filename和Entry::write_to_disk.但是,我有一些方法对常规文件和目录都没有意义.例如,Entry::iter_contents遍历目录的所有子条目.
我希望能够定义某些方法,例如Entry::iter_contents仅针对entry_type某个变体的条目.
我尝试EntryType变成一个特征并制作了一个DirectoryEntryInfo和FileEntryInfo结构,两者都实现了EntryType.
可悲的是,这种方法存在一些问题.我有一个Vec<Entry>其他地方,这种变化将成为Vec<Entry<EntryType>>.使用这样的特质,我也没有办法垂头丧气Entry<EntryList>来Entry<DirectoryEntryInfo>.我也尝试过做一些事情Any,因为这是我所知道的唯一一种在Rust中贬低的方式,但我只能投entry_type,而不是整个Entry本身.
最终,我想最终得到类似的东西: …
以下代码几乎是Apple Documentation的精确复制品,编译时没有错误:
guard let firstItem = (rawItems! as? Array<Dictionary<String, Any>>)?.first else {
throw AnError()
}
let identityRef = firstItem[kSecImportItemIdentity as String]
as! SecIdentity? // !!!
guard let identity = identityRef else {
throw AnError()
}
Run Code Online (Sandbox Code Playgroud)
标有的行!!!包含强制向下转换,而替换as!为as显然会导致编译错误'Any?' is not convertible to 'SecIdentity?'...确实SecIdentity是一个类,Any甚至可能不是一个类。
我真正无法解释的是以下内容。如果我尝试使代码更安全,请使用此
guard let idenity = firstItem[kSecImportItemIdentity as String] as? SecIdentity
else {
throw AnError()
}
Run Code Online (Sandbox Code Playgroud)
或这个
guard let idenityRef = firstItem[kSecImportItemIdentity as String] as? SecIdentity? …Run Code Online (Sandbox Code Playgroud) downcast ×10
c++ ×7
dynamic-cast ×2
c# ×1
enums ×1
generics ×1
inheritance ×1
oop ×1
rust ×1
static-cast ×1
swift ×1
templates ×1
type-safety ×1
unique-ptr ×1