首先完全免责声明:我没有编译这个示例代码,也没有编译真正的代码(嗯,至少完全部署)。我仍然在思考这个问题。考虑到这一点,假设我们有这样的类结构:
一个 super 基类,我们将使用它来将具有该基类的实例存储在同一容器中,还有一些“Facet”类,我们将使用多个继承来封装常见行为。
class Facet_A;
class Facet_B;
class Facet_C;
struct Facet_converter
{
Facet_A * facet_a;
Facet_B * facet_b;
Facet_C * facet_c;
};
class Super_base
{
public:
virtual ~Super_base() {}
virtual Facet_converter convert()=0;
virtual const Facet_converter convert()const=0; //Notice this const...
};
class Facet_A
{
private:
int value_a;
public:
virtual ~Facet_A() {}
Facet_A():value_a(0) {}
void set_value_a(int v) {value_a=v;}
int get_value_a() const {return value_a;}
};
class Facet_B
{
private:
float value_b;
public:
Facet_B():value_b(0) {}
virtual ~Facet_B() {}
void set_value_b(float v) {value_b=v;}
float get_value_b() const {return value_b;}
};
class Facet_C
{
private:
char value_c;
public:
Facet_C():value_c('a') {}
virtual ~Facet_C() {}
void set_value_c(char v) {value_c=v;}
char get_value_c() const {return value_c;}
};
从这些派生的所有类将始终:
- 将 Super_base 用作公共(public)基类,因此我们可以将它们存储在这些 vector 中。
- 实现转换方法,该方法将返回一个 Facet_converter 对象,该对象具有派生类的指针(共享、唯一、原始等),转换为特定方面(如果不适用,则为 null)。
- 使用 Facet_A、Facet_B 或 Facet_C 作为基类,具体取决于他们尝试实现的内容。
客户端代码会做类似...
std::vector<Super_base *> v;
//Fill super base with the good stuff.
//Let's use everything that has an integer!.
for(auto sb : v)
{
Facet_converter fc=sb->convert();
if(fc.facet_a)
{
//Do something with this integer like... std::cout<<fc.facet_a->get_value_a()<<std::endl;
}
}
//Let's use everything that has a float.
for(auto sb : v)
{
Facet_converter fc=sb->convert();
if(fc.facet_b)
{
//Do something with this float...
}
}
//Let's use everything that has a char.
for(auto sb : v)
{
Facet_converter fc=sb->convert();
if(fc.facet_c)
{
//You get the drift...
}
}
糟糕的设计(我已经厌倦了到处都是访客)这个特定的例子几乎是准系统,但你明白我想要做的:在不使用 dynamic_cast 和“强制”编译器的情况下降低层次结构帮助(如果我尝试在“转换”方法中对非基类进行赋值,它会冲我大喊大叫)。
所以,一个完全实现的类...
class Derived_numeric: //This one has a float and and int
public Super_base,
public Facet_A,
public Facet_B
{
///Blah blah blah blah
virtual Facet_converter convert()
{
Facet_converter result;
result.facet_a=this;
result.facet_b=this;
result.facet_c=nullptr; //Assume no constructor for the struct that initializes the method, not really the case.
return result;
}
virtual const Facet_converter convert()const
{
const Facet_converter result;
result.facet_a=this; //Booom!!!. Error, const Derived_numeric can't be caster to Facet_A because... it's const.
result.facet_b=this;
result.facet_c=nullptr;
return result;
}
}
问题就出在 const convert 方法中。有一个 const 和一个非 const 方法,因为客户端代码可以使用 const 和非 const 对象,但是编译器不可能让我分配一个“const this”而不先进行 const 转换。
考虑到我有两个解决方案:
- const_casting 常量方法中的 this 指针。
- 创建两个 Facet_converter 对象:Facet_converter 和 Facet_converter_const。它们完全相同,但一个具有 const 指针,另一个具有常规指针。让客户代码使用他们需要的代码。
他们都遭受可怕的代码重复,因为代码几乎相同,只有少数细节发生变化。
我考虑过只实现 const 的想法,对“this”指针进行 const_casting,并且基本上在该方法所 promise 的内容上撒谎。想要真正的 constness 吗?将 const 修饰符添加到 convert() 的结果并完成它......看起来更容易,但太偷偷摸摸了。
我的问题是,我是否可以在不基本上复制粘贴代码和偷偷摸摸的情况下实现这个想法?请记住,我同时需要 const 和非 const(派生对象可能会通过使用方面更改其状态,也可能不会)。
现在,请考虑我不是在寻找“你的方法是错误的”或“我不知道你为什么要那样做”。这就是我想要应对和了解的现状。我已经知道我可以使用双重调度,或者我可以将整个基类混为一谈以包含所有其他可能性......我只是在寻找它的替代方案。
最佳答案
您可以创建 Super_base
的 const Facet_converter
成员,然后通过构造函数对其进行设置。
class Super_base
{
protected:
const Facet_converter implementations;
public:
Super_base( const Facet_converter& implementations )
: implementations( implementations ) {};
virtual ~Super_base() {};
const Facet_converter& convert() const { return implementations; }
};
当你实现派生类时,做:
Derived_numeric::Derived_numeric( ) : Super_base( Facet_converter( this, this, NULL ) )
您还需要为该结构添加一个构造函数,以便可以调用:
struct Facet_converter
{
Facet_converter( Facet_A* const& a, Facet_B* const& b, Facet_C* const& c )
{
facet_a = a;
facet_b = b;
facet_c = c;
}
Facet_A * facet_a;
Facet_B * facet_b;
Facet_C * facet_c;
};
我还没有使用实际的指针和子类对此进行测试,因此它可能需要一些调整。
关于c++ - 多态和通过带指针的结构进行转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31885499/