【问题标题】:How to access public data member of base class?如何访问基类的公共数据成员?
【发布时间】:2014-01-12 15:13:26
【问题描述】:

如何访问派生类中的基类数据成员? 我想使用 docElem 数据成员,它已经在 subMenuLists::changeWidget() 中初始化了 customizeCSMWindow()constructor。

class myWidget
{
public :
    QDomElement docElem; 
    QDomDocument *menuOrderXMLFile;
};

class subMenuLists : public QListWidget , public myWidget
{
        Q_OBJECT
 public slots:
        void changeWidget( int index);
};

class customizeCSMwindow : public QDialog , public myWidget
{
    Q_OBJECT
public :
    subMenuLists *menuList;
    customizeCSMwindow(QString);       

}

customizeCSMwindow::customizeCSMwindow(QString fileName)
{
menuOrderXMLFile = new QDomDocument();
file = new QFile(fileName);
QString errorStr;
int errorLine;
int errorColumn;
if(!menuOrderXMLFile->setContent(file, false , &errorStr, &errorLine,
                             &errorColumn))
   std::cout<<"not found \n";
 else
       docElem = menuOrderXMLFile->documentElement();
}

void subMenuLists::changeWidget(int index)
{
    clear();
// How to access that docElem here??
}

如何访问void subMenuLists::changeWidget()函数中的docElem

编辑

我想解释一下我的问题,看看你能不能帮助我。我想要的是,在subMenuList::changeWidget() 函数中获取cusomizeCSMWidnow 构造函数中分配的docElem 的值。截至目前,当我在 changeWidget 函数中访问 docElem 时,它会给出 null/未初始化的值。

【问题讨论】:

  • 什么是Q_OBJECT?顺便说一句 - 拥有公共数据成员不是一个好主意。最好有 getter 和 setter
  • 随便用吧:docElem.doWhatever();??
  • 允许访问 docElem,但问题是我没有得到在 customizeCSMWindow 的构造函数中分配给它的 docElem 的值。我错过了什么吗?
  • @EdHeal 请忽略 Q_OBJECT 的事情。我想解释一下我的问题,看看你能不能帮助我。我想要的是,获取在 subMenuList::changeWidget() 函数的 cusomizeCSMWidnow 构造函数中分配的 docElem 的值。截至目前,当我在 changeWidget 函数中访问 docElem 时,它给出了 null/未初始化的值。
  • 你错过了一些东西。你真正设置了什么,你可以访问什么?!看我的回答!

标签: c++


【解决方案1】:

customizeCSMwindow 类类似于subMenuLists 类型元素的容器。容器和元素各有成员docElem。您尝试在subMenuLists 中访问容器customizeCSMwindow 的成员docElem

这不能直接工作。要么给容器的元素一个指向容器的指针,要么在subMenuLists::changeWidget的调用中给容器的指针。

解释元素中指向容器的指针的示例:

#include <string>
#include <iostream>

class myWidget
{
public :
    std::string docElem;
};

class customizeCSMwindow;

class subMenuLists : public myWidget
{
    customizeCSMwindow* m_pContainer; // Pointer to the container
public:
    subMenuLists(customizeCSMwindow* pContainer) :
        m_pContainer(pContainer)
    {}
    void changeWidget(int index);
};

class customizeCSMwindow : public myWidget
{
public:
    subMenuLists *menuList; // This pointer makes customizeCSMwindow to a container.
    customizeCSMwindow();
    void setMenuList(subMenuLists* ml) {
        menuList = ml;
    }
};

customizeCSMwindow::customizeCSMwindow() // Here we set docElem of the **container**.
{
    docElem = " docElem in customizeCSMwindow";
}

void subMenuLists::changeWidget(int index) // In the **element** we want to access the  docElem of the **container**
{
    // How to access that docElem here??
    std::cout << "\nIn changeWidget:" << m_pContainer->docElem << "\n";
}

int main() {
    customizeCSMwindow job;
    subMenuLists menu(&job);

    job.setMenuList(&menu);

    menu.changeWidget(0);
}

在 cmets 中,您问:“还有一件事,这个设计看起来不错吗?或者您能提出更好的方法来获得相同的变量,即 docElem 在两个不同的类中可访问?”

这在很大程度上取决于目标。如果menuList 中可以有多个元素,则应避免使用原始指针。您应该改用 std::vectorstd::shared_ptr。如果这只是某种指针实现 pimpl(参见 Scott Meyers 有效的 c++),那么原始指针就可以了。

关于好的实现有太多要说的了。您需要阅读相关书籍(例如,标准书籍 [Stroustrup: C++] 或 [Scott Meyers: Effective C++] 或通过 google 在讨论中轻松找到的良好参考资料)。

menuList 中的多个元素只有一种可能的实现方式。

#include <string>
#include <iostream>
#include <stdexcept> // for std::out_of_range
#include <memory> // for std::shared_ptr
#include <vector>

class myWidget
{
public :
    std::string docElem;
};

class customizeCSMwindow;

class subMenuLists : public myWidget
{
    customizeCSMwindow* m_pContainer; // Pointer to the container

    /* The private constructor only allows the friend customizeCSMwindow to
       construct elements of subMenuLists. This makes sure that pContainer is right. */
    subMenuLists(customizeCSMwindow* pContainer) :
        m_pContainer(pContainer)
    {}
public:
    void changeWidget(int index);

    friend customizeCSMwindow;
};

class customizeCSMwindow : public myWidget
{
    /* shared_ptr takes care of the deletion of allocated memory for subMenuLists. */
    typedef std::shared_ptr<subMenuLists> pSubMenuLists_t;

    /* Automatically runs the destructors of the elements when menuList is destructed. */
    std::vector<pSubMenuLists_t> menuList; // This pointer makes customizeCSMwindow to a container.
public:
    customizeCSMwindow();

    /* The only and right way to generate new MenuLists. Takes care of the right m_pContainer. */
    void addMenuLists(/*Stuff needed for the construction of an element of type subMenuLists*/) {
        pSubMenuLists_t ml(new subMenuLists(this /* stuff for subMenuLists */));
        menuList.push_back(ml);
    }

    /* One possible interface to make iteration over menuList possible. (There are other ways too.) */
    size_t sizeMenuList() {
        return menuList.size();
    }
    subMenuLists* getMenuListItem(size_t i) throw(std::out_of_range)
    {
        return menuList.at(i).get(); 
    }
};

customizeCSMwindow::customizeCSMwindow() // Here we set docElem of the **container**.
{
    docElem = " docElem in customizeCSMwindow";
}    
void subMenuLists::changeWidget(int index) // In the **element** we want to access the  docElem of the **container**
{
    // How to access that docElem here??
    std::cout << "\nIn changeWidget:" << m_pContainer->docElem << "\n";
}

int main() {
    size_t i;
    customizeCSMwindow job;

    job.addMenuLists();

    for(i=0; i!=job.sizeMenuList(); i++)
        job.getMenuListItem(i)->changeWidget(0);

    return 0;
}

/*
    Local Variables:
    compile-command: "g++ -std=c++11 test3.cc -o a.exe; ./a.exe"
    End:
 */

【讨论】:

  • 谢谢@Tobias,我明白了。还有一件事,这个设计好看吗?或者你能建议任何更好的方法来拥有相同的变量,即 docElem 在两个不同的类中可访问?
  • 我是 C++/OOPs 编程的新手,所以我想知道这个“容器”是否是标准的? ps:顺便说一句,我喜欢这种方法:)
  • 我已经编辑了答案。答案中的第一个示例以最简单的方式显示了问题。第二个示例显示了一种可能的实现,其中包含一些保护措施。但是,正如答案中所述。一个实现是否有优点或缺点也很大程度上取决于目标。
  • 感谢@tobias。我需要阅读您提到的那些书才能更好地理解第二种解决方案。但是,这个答案很有帮助。谢谢!
【解决方案2】:

派生类可以访问父类的公共和受保护成员。 您只需使用docElem,就好像它是subMenuLists 的成员一样。

【讨论】:

  • 允许访问 docElem,但问题是我没有得到在 customizeCSMWindow 的构造函数中分配给它的 docElem 的值。我错过了什么吗?
【解决方案3】:

继承的主要目的是使基类中的公共(和受保护)数据和函数可供派生类使用,就好像这些数据和函数是在派生类本身中声明的一样。

例如:

class BASE {
public:
   int baseData; //the data you want to use
   void workOnBaseData(){
      baseData = 5;
   }
}; 

class DERIVED : public BASE {
public:
   int someData; //data member of the derived class
   void workOnBaseAndSomeData(){
      someData = baseData; //baseData is already known to DERIVED via inheritance
   }
};

执行此代码后,发现 someData = 5! 希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-30
    • 2014-10-27
    • 2015-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-10
    相关资源
    最近更新 更多