CRTP / 宏 / 避免转换派生指针 class
CRTP / Macros / Avoid casting pointer of derived class
最近我一直在做一些项目,但遇到了这样的情况,我们需要能够做这样的事情。
#define TYPED(Type) \
virtual Type *typedThis() const { return (Type*) this; }
class A {
public:
TYPED(A)
virtual void describe() { std::cout << "I am type A\n"; }
static int x;
};
int A::x = 1;
class B : public A {
public:
TYPED(B)
virtual void describe() { std::cout << "I am type B\n"; }
static int x;
};
int B::x = 2;
int
main(int argc, char** argv)
{
B* b = new B();
A* b2 = b;
b->describe();
b2->describe();
std::cout << b->typedThis()->x << std::endl;
std::cout << b2->typedThis()->x << std::endl; // AQUI DEBERIA DAR 2 !! :c
}
这当然只是一个玩具示例。我们想要做的事情的基本思想是定义一个函数 typedThis() ,它将指针转换为正确的类型,然后访问正确的变量 x,并打印出 2 而不是 1。
但是,输出如下:
I am type B
I am type B
2
1 //Here should also be 2
我发现真正有趣的是虚拟方法 describe() 似乎按照我们想要的方式工作。因此,我可以推断 typedThis() 方法也按照我们希望的方式工作。但如果是这样,为什么 C++ 将此指针视为 A* 而不是 B*。如果 C++ 将此指针视为 B*,那么它会使用正确的变量 x。 谁能给我解释一下吗?
我试过使用 CRTP,但是我觉得这不会让事情变得更简单,因为在项目中我们将使用很多(很多)不同的 类,它们不断地在它们之间派生,我看到一些关于如何在具有多重继承时使用 CRTP 的文章,但是它们真的很混乱并且很难与我们现有的东西集成。
我删除了示例中的所有干扰:
class A {
public:
virtual A *typedThis() const { return (A*) this; }
static int x = 1;
};
class B : public A {
public:
virtual B *typedThis() const { return (B*) this; }
static int x = 2;
};
int main()
{
B* b1 = new B;
A* b2 = b1;
std::cout << b1->typedThis()->x << "\n";
std::cout << b2->typedThis()->x << "\n";
}
typedThis
什么都不做。
b1->typedThis()
returns a B*
指向 B
.
同样,b1
本身是一个 B*
,它指向一个 B
。
b2->typedThis()
returns 一个 A*
指向一个 B
.
同样,b2
本身是一个 A*
,指向 B
。
所以b1->typedThis()
与b1
相同,b2->typedThis()
与b2
相同,示例的最后两行等同于:
std::cout << b1->x << "\n";
std::cout << b2->x << "\n";
另请注意,您的 C 风格转换会丢弃对象的 const
限定符。
最近我一直在做一些项目,但遇到了这样的情况,我们需要能够做这样的事情。
#define TYPED(Type) \
virtual Type *typedThis() const { return (Type*) this; }
class A {
public:
TYPED(A)
virtual void describe() { std::cout << "I am type A\n"; }
static int x;
};
int A::x = 1;
class B : public A {
public:
TYPED(B)
virtual void describe() { std::cout << "I am type B\n"; }
static int x;
};
int B::x = 2;
int
main(int argc, char** argv)
{
B* b = new B();
A* b2 = b;
b->describe();
b2->describe();
std::cout << b->typedThis()->x << std::endl;
std::cout << b2->typedThis()->x << std::endl; // AQUI DEBERIA DAR 2 !! :c
}
这当然只是一个玩具示例。我们想要做的事情的基本思想是定义一个函数 typedThis() ,它将指针转换为正确的类型,然后访问正确的变量 x,并打印出 2 而不是 1。
但是,输出如下:
I am type B
I am type B
2
1 //Here should also be 2
我发现真正有趣的是虚拟方法 describe() 似乎按照我们想要的方式工作。因此,我可以推断 typedThis() 方法也按照我们希望的方式工作。但如果是这样,为什么 C++ 将此指针视为 A* 而不是 B*。如果 C++ 将此指针视为 B*,那么它会使用正确的变量 x。 谁能给我解释一下吗?
我试过使用 CRTP,但是我觉得这不会让事情变得更简单,因为在项目中我们将使用很多(很多)不同的 类,它们不断地在它们之间派生,我看到一些关于如何在具有多重继承时使用 CRTP 的文章,但是它们真的很混乱并且很难与我们现有的东西集成。
我删除了示例中的所有干扰:
class A {
public:
virtual A *typedThis() const { return (A*) this; }
static int x = 1;
};
class B : public A {
public:
virtual B *typedThis() const { return (B*) this; }
static int x = 2;
};
int main()
{
B* b1 = new B;
A* b2 = b1;
std::cout << b1->typedThis()->x << "\n";
std::cout << b2->typedThis()->x << "\n";
}
typedThis
什么都不做。
b1->typedThis()
returns a B*
指向 B
.
同样,b1
本身是一个 B*
,它指向一个 B
。
b2->typedThis()
returns 一个 A*
指向一个 B
.
同样,b2
本身是一个 A*
,指向 B
。
所以b1->typedThis()
与b1
相同,b2->typedThis()
与b2
相同,示例的最后两行等同于:
std::cout << b1->x << "\n";
std::cout << b2->x << "\n";
另请注意,您的 C 风格转换会丢弃对象的 const
限定符。