1

它适用于常规课程:

class Base
{
public:
    Base() {}
protected:
    int* a;
};

class Derived : public Base
{
public:
    Derived() {}
    void foo() {
        int** pa = &a;
    }
};

int main() {
    Derived* d = new Derived();
    d->foo();
    delete  d;
}

Base但是当和Derived类使用模板时会报错:

'int* Base<int>::a' 在此上下文中受到保护

template<typename T>
class Base
{
public:
    Base() {}
protected:
    int* a;
};

template<typename T>
class Derived : public Base<T>
{
public:
    Derived() {}
    void foo() {
        int** pa = &Base<T>::a;
    }
};

int main() {
    Derived<int>* d = new Derived<int>();
    d->foo();
    delete d;
}

这是为什么?

4

1 回答 1

3

该错误大多与模板无关,并且在没有任何继承的情况下也会发生。简单的问题是表达式 &Base<T>::a被解析为指向成员的指针,如下面的片段所示:

#include <iostream>
#include <typeinfo>
using namespace std;

class B
{
public:
    void foo()
    {
        int* B::* pa = &B::a;
        int** pi = &(B::a);

        cout << typeid(pa).name() << endl;
        cout << typeid(pi).name() << endl;
    }

protected:
    int* a;
};

struct D : public B
{
    // Access to B::a is perfectly fine.
    int* B::* pa = &B::a;

    // But this causes a type error:
    // "cannot convert from 'int *B::* ' to 'int **'
    // int** pi = &B::a;
    
    // Parentheses help to get the address of this->a ...
    int** pi2 = &(B::a);

    // ... and writing this->a helps, too ;-).
    int **pi3 = &this->a;

    // Of course, outside of templates we can simply write a!
    int** pi4 = &a;
};

int main()
{
    B b;
    b.foo();
}

输出是:

int * B::*
int * *

模板是错误出现的地方,因为我们被迫限定从属名称,因此无意中以指向成员的结构结束。

评论部分中的两种解决方案都有效:您可以简单地编写&this->a,或者像我在这里所做的那样,将合格的成员放在括号中。我不清楚后者为什么起作用:operator::()具有最高优先级,因此括号不会改变这一点。

正如人们所期望的那样,在派生类中获取受保护基类成员的地址是完全可能的。据我所知,涉及模板时的错误消息是不正确且具有误导性的(但是当我认为这是编译器的错时,我通常是错的……)。

于 2021-08-30T21:40:17.607 回答