嵌套类成员函数无法访问封闭类的功能。为什么?

时间:2010-06-17 01:07:59

标签: c++ nested-class

请参阅以下示例代码:

class A
{
private:
    class B
    {
    public:
        foobar();
    };
public:
    foo();
    bar();
};

在A级和A级之内B实施:

A::foo()
{
    //do something
}

A::bar()
{
    //some code
    foo();
    //more code
}

A::B::foobar()
{
    //some code
    foo(); //<<compiler doesn't like this
}

编译器在方法foobar()中标记对foo()的调用。早些时候,我把foo()作为A类的私有成员函数,但是改为public,假设B的函数看不到它。当然,它没有帮助。我试图重新使用A的方法提供的功能。为什么编译器不允许这个函数调用?在我看来,它们是同一个封闭类(A)的一部分。我认为嵌套类meebers在C ++标准中封装类的可访问性问题已得到解决。

如果没有为B重写相同的方法(foo()),保持B嵌套在A中,我怎样才能实现我想做的事?

我正在使用VC ++编译器ver-9(Visual Studio 2008)。谢谢你的帮助。

5 个答案:

答案 0 :(得分:19)

foo()A的非静态成员函数,您试图在没有实例的情况下调用它。
嵌套类B是一个单独的类,只具有一些访问权限,并且对A的现有实例没有任何特殊知识。

如果B需要访问A,您必须为其提供引用,例如:

class A {
    class B {
        A& parent_;
    public:
        B(A& parent) : parent_(parent) {}
        void foobar() { parent_.foo(); }
    };
    B b_;
public:
    A() : b_(*this) {}
};

答案 1 :(得分:1)

这是一个自动化的,虽然可能是非便携式的技巧(虽然从6.0开始就在VC ++上工作)。 B级必须是A级成员才能工作。

#ifndef OUTERCLASS
#define OUTERCLASS(className, memberName) \
    reinterpret_cast<className*>(reinterpret_cast<unsigned char*>(this) - offsetof(className, memberName))
#endif 

class A
{
private:
    class B
    {
    public:
        void foobar() {
           A* pA = OUTERCLASS(A, m_classB);
           pA->foo();
        }
    } m_classB;
public:
    foo();
    bar();
};

答案 2 :(得分:0)

如果要重用A中的功能,则应该从A继承而不是嵌套在其中。

答案 3 :(得分:0)

基本上是Georg Fritzsche所说的

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

class A
{
private:
    class B
    {
     A& parent_;
     public:
        //B();  //uncommenting gives error
        ~B();
        B(A& parent) : parent_(parent) {}

        void foobar() 
        { 
         parent_.foo();  
         cout << "A::B::foo()" <<endl; 
        }

        const std::string& foobarstring(const std::string& test) const 
        { 
         parent_.foostring(test); cout << "A::B::foostring()" <<endl;
        }
    };
public:
    void foo();
    void bar();
    const std::string& foostring(const std::string& test) const;
    A(); 
    ~A(){};
    B b_;
};

//A::B::B() {}; //uncommenting gives error
A::B::~B(){};

A::A():b_(*this) {}


void A::foo()
{
    cout << "A::foo()" <<endl;
}

const std::string& A::foostring(const std::string& test) const
{
    cout << test <<endl;
    return test;
}

void A::bar()
{
    //some code
    cout << "A::bar()" <<endl;
    foo();
    //more code
}

int main(int argc, char* argv[])
{
A a;
a.b_.foobar();
a.b_.foobarstring("hello");

return 0;
}

如果取消注释默认的B构造函数,则会出现错误

答案 4 :(得分:0)

结合 Igor Zevaka 和热情极客的回答。另外,使用 reinterpret_cast 计算偏移量(如果您使用 new 关键字创建类成员变量):

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

template < typename T, typename U > constexpr size_t offsetOf(U T:: *member)
{
    return (char*) &((T*) nullptr->*member) - (char*) nullptr;
}

class A
{
    private:
        class B
        {
         public:
            B(string message);
            ~B();

            void foobar()
            {
                A *pA = reinterpret_cast<A*> (reinterpret_cast< unsigned char*> (this) - offsetOf(&A::b_));
                pA->foo();
                pA->bar();
                std::cout << "DONE!";
            }
        };
    public:
        void foo();
        void bar();
        A();
        ~A() {};
        B* b_ = new B("Hello World!");
};

A::A() 
{
    cout << "A constructor\n";
};
A::B::B(string message) {
    cout << "B constructor\n";
    cout << "Message =  " << message << "\n";
};
A::B::~B() {};

void A::foo()
{
    cout << "A::foo()" << endl;
}

void A::bar()
{
    cout << "A::bar()" << endl;
    foo();
}

int main(int argc, char *argv[])
{
    A* a = new A();
    a->b_->foobar();

    return 0;
}

输出:

B constructor
Message =  Hello World!
A constructor
A::foo()
A::bar()
A::foo()
DONE!

参考文献:

https://stackoverflow.com/a/10607424/9524565

https://stackoverflow.com/a/3058382/9524565

https://stackoverflow.com/a/20141143/9524565