Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ CRTP/宏/避免转换派生类的指针_C++_Pointers_Multiple Inheritance_C Preprocessor_Crtp - Fatal编程技术网

C++ CRTP/宏/避免转换派生类的指针

C++ CRTP/宏/避免转换派生类的指针,c++,pointers,multiple-inheritance,c-preprocessor,crtp,C++,Pointers,Multiple Inheritance,C Preprocessor,Crtp,最近我在一个项目中工作,我们遇到了一种情况,我们需要能够做这样的事情 #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

最近我在一个项目中工作,我们遇到了一种情况,我们需要能够做这样的事情

#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
}
我发现真正有趣的是,virtual方法descripe()似乎按照我们想要的方式工作。因此,我可以推断方法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";
}

还要注意的是,C样式转换会丢弃对象的限定符
const

如果不是虚拟的,为什么应该是2?它将使用指针基类进行解析,而不是检查任何虚拟表来解析该函数。pba需要是虚拟的。是。因为这只是一个玩具示例,所以我使用了一个虚拟方法,只打印出一个数字。但在实际代码中,我们希望访问一些在类之间具有相同名称的属性。因此,假设A和B类都有int静态属性x。然后我们收到一个指针a*,但带有一个实例B的指针。如果我们想得到x的值。我们得到的是类A的x值,而不是类B的x值。在本例中,这相当于说,我们使用A的方法pba()而不是B的方法pba()打印。对
x
的访问只使用表达式的类型,而不是实际值,因为它是类的属性而不是对象的属性。由于
b->typedThis()
是一个
b*
,因此您可以得到
b::x
。但是,
b2->typedThis()
是一个
A*
,因此您可以得到
A::x
b2
指向a
B
的事实并不重要。它并没有完全解决我的问题,但却是最有用的答案,谢谢!
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";
}
    std::cout << b1->x << "\n";
    std::cout << b2->x << "\n";