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

发布于 2024-09-05 19:51:03 字数 681 浏览 3 评论 0原文

请参阅下面的示例代码:

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 的私有成员函数,但更改为公共,假设 B 的函数看不到它。当然,这没有帮助。我正在尝试重用 A 的方法提供的功能。为什么编译器不允许这个函数调用?在我看来,它们属于同一封闭类 (A)。我认为嵌套类 meebers 在 C++ 标准中封装类的可访问性问题已经解决。

我如何才能实现我想要做的事情,而不为 B 重写相同的方法 (foo()),从而使 B 嵌套在 A 中?

我使用的是 VC++ 编译器版本 9 (Visual Studio 2008)。感谢您的帮助。

Please see the example code below:

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

Within class A & B implementation:

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

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

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

The compiler flags the call to foo() within the method foobar(). Earlier, I had foo() as private member function of class A but changed to public assuming that B's function can't see it. Of course, it didn't help. I am trying to re-use the functionality provided by A's method. Why doesn't the compiler allow this function call? As I see it, they are part of same enclosing class (A). I thought the accessibility issue for nested class meebers for enclosing class in C++ standards was resolved.

How can I achieve what I am trying to do without re-writing the same method (foo()) for B, which keeping B nested within A?

I am using VC++ compiler ver-9 (Visual Studio 2008). Thank you for your help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

时间你老了 2024-09-12 19:51:03

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) {}
};

foo() is a non-static member function of A and you are trying to call it without an instance.
The nested class B is a seperate class that only has some access privileges and doesn't have any special knowledge about existing instances of A.

If B needs access to an A you have to give it a reference to it, e.g.:

class A {
    class B {
        A& parent_;
    public:
        B(A& parent) : parent_(parent) {}
        void foobar() { parent_.foo(); }
    };
    B b_;
public:
    A() : b_(*this) {}
};
归途 2024-09-12 19:51:03

这是一个自动的技巧,尽管可能不可移植(尽管从 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();
};

This is an automagic, albeit possibly nonportable trick (worked on VC++ since 6.0 though). Class B has to be a member of class A for this to work.

#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();
};
白云悠悠 2024-09-12 19:51:03

基本上就是 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 构造函数,你会得到一个错误

Basically what Georg Fritzsche said

#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;
}

If you uncomment the default B constructor you would get an error

执笏见 2024-09-12 19:51:03

如果你想重用 A 的功能,那么你应该继承 A 而不是在其中嵌套 B。

If you want to reuse functionality from A then you should inherit from A not nest B inside it.

岁月流歌 2024-09-12 19:51:03

结合 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

Combining Igor Zevaka's and enthusiasticgeek's answers. Also, using reinterpret_cast for calculating offset (If you create class member variable using new keyword):

#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;
}

Output:

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

References:

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

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文