C++ 嵌套类让我发疯

C++ Nested classes driving me crazy

提问人:SMeyers 提问时间:10/26/2008 最后编辑:Don KirkbySMeyers 更新时间:12/29/2012 访问量:17744

问:

我正在尝试编译这段非常简单的代码

class myList
{
public:
    std::vector<std::string> vec;
    class Items
    {
    public:
        void Add(std::string str)
        {
            myList::vec.push_back(str);
        };
    }items;
};

int main()
{
    myList newList;
    newList.items.Add("A");
}

我能做些什么来使这项工作不创建更多需要或过于复杂的东西的对象......

嵌套的 C++

评论


答:

15赞 richq 10/26/2008 #1

添加几个构造函数和一个指向父类的指针。

#include <string>
#include <vector>
class myList
{
public:
    std::vector<std::string> vec;
    myList(): items(this) {} // Added
    class Items
    {
    public:
        Items(myList *ml): self(ml) {}  // Added
        void Add(std::string str)
        {
                self->vec.push_back(str); // Changed
        };
        myList *self; //Added
    }items;
};

int main()
{
    myList newList;
    newList.items.Add("A");
}

您需要 myList() 构造函数,以便它向内部类成员变量的实例注册自身的实例。然后,需要 Items 构造函数来存储指向外部 myList 类实例的指针。最后,在 Add 方法中,您需要在存储的 myList 实例中引用 vec。

正如 Catskul 所指出的,Item 构造函数实际上不能对它接收的 myList 指针执行任何操作。我还想说,虽然这个答案更接近最初的意图,但 steveth45 的答案更接近你想在真实程序中做的事情。

评论

0赞 SMeyers 10/26/2008
非常感谢,这有效,但我希望存在一个更简单的版本,但我必须继续应对 C++ 固执:-(希望C++0能解决其中的一些怪癖
1赞 Catskul 10/1/2009
...但是,在 MyList 仍在构造时,请小心将此指针传递给 MyList。如果 Items 构造函数执行任何最终过早使用 MyList this 指针的操作,它可能会给自己带来麻烦。
11赞 postfuturist 10/26/2008 #2

这样,您就不会直接公开您的班级成员。你的例子似乎有点过度架构。为什么要将 std::vector 放入类中,然后将其公开为公共?

class myList
{
private:
    std::vector<std::string> vec;
public:
    void Add(std::string str)
    {
        vec.push_back(str);
    };
};

int main()
{
    myList newList;
    newList.Add("A");
}

评论

2赞 Joe Soul-bringer 2/26/2010
原作者可能需要内类结构来处理他没有提到的其他东西(为了简化他的阐述)。鉴于现有信息,您对软件工程软方面的看法是正确的,但这个问题似乎是一个“玩具”,抽象编译问题最初可能是一个相当复杂的算法。这并不重要,你可能已经明白了,我只是说......
2赞 Dave Hillier 10/26/2008 #3

内部类仅按名称相关。你不能像这样引用基类中的向量。

您需要将向量移动到内部类或存储对它的引用。

5赞 Rob Walker 10/26/2008 #4

与 Java 不同,C++ 中的内部对象无法访问外部“this”指针......如果你仔细想想,可能有些情况没有参考。

Richard Quirk 的解决方案是您在 C++ 中可以得到的最接近的解决方案

0赞 phoku 10/2/2009 #5

您可以通过以下构造来简化此操作:

typedef std::vector<std::string> myList;

真的为什么不直接使用 STL 向量呢? 这样,您可以让所有标准算法都与 数据。

1赞 nickdu 12/29/2012 #6

虽然这篇文章已经有几年的历史了,但我也许可以添加一些有用的东西。虽然我会说原始帖子中的类设计看起来不是那么好,但有时让嵌入类能够访问包含的类很有用。这可以很容易地完成,而无需存储额外的指针。下面是一个示例。它应该可以工作,因为我从一些现有代码中获取了它并更改了一些名称。关键是 EmbeddorOf 宏。像魅力一样工作。

.h 文件/////////////////////////

struct IReferenceCounted
{
    virtual unsigned long AddRef() = 0;
    virtual unsigned long Release() = 0;
};

struct IFoo : public IReferenceCounted
{
};

class Foo : public IFoo
{
public:
    static IFoo* Create();
    static IFoo* Create(IReferenceCounted* outer, IReferenceCounted** inner);

private:
    Foo();
    Foo(IReferenceCounted* outer);
    ~Foo();

    // IReferenceCounted

    unsigned long AddRef();
    unsigned long Release();

private:
    struct EIReferenceCounted : IReferenceCounted
    {
        // IReferenceCounted

        unsigned long AddRef();
        unsigned long Release();
    } _inner;

    unsigned long _refs;
    IReferenceCounted* _outer;
};

.cpp 文件/////////////////

#include <stdio.h>
#include <stddef.h>
#include "Foo.h"

#define EmbeddorOf(class, member, this) \
    (class *) ((char *) this - offsetof(class, member))

// Foo

Foo::Foo() : _refs(1), _outer(&this->_inner)
{
}

Foo::Foo(IReferenceCounted* outer) : _refs(1), _outer(outer)
{
}

Foo::~Foo()
{
    printf("Foo::~Foo()\n");
}

IFoo* Foo::Create()
{
    return new Foo();
}

IFoo* Foo::Create(IReferenceCounted* outer, IReferenceCounted** inner)
{
    Foo* foo = new Foo(outer);
    *inner = &foo->_inner;
    return (IFoo*) foo;
}

// IReferenceCounted

unsigned long Foo::AddRef()
{
    printf("Foo::AddRef()\n");
    return this->_outer->AddRef();
}

unsigned long Foo::Release()
{
    printf("Foo::Release()\n");
    return this->_outer->Release();
}

// Inner IReferenceCounted

unsigned long Foo::EIReferenceCounted::AddRef()
{
    Foo* pThis = EmbeddorOf(Foo, _inner, this);
    return ++pThis->_refs;
}

unsigned long Foo::EIReferenceCounted::Release()
{
    Foo* pThis = EmbeddorOf(Foo, _inner, this);
    unsigned long refs = --pThis->_refs;
    if (refs == 0)
        {

        // Artifically increment so that we won't try to destroy multiple
        // times in the event that our destructor causes AddRef()'s or
        // Releases().

        pThis->_refs = 1;
        delete pThis;
        }
    return refs;
}

缺口