虚函数的这两个定义之间有什么区别?[复制]

What's the difference between these two definitions of a virtual function? [duplicate]

提问人:Rodo 提问时间:7/1/2023 最后编辑:Remy LebeauRodo 更新时间:7/1/2023 访问量:95

问:

我在一个名为TouchGFX的东西中遇到了一个错误,有人向我指出,类中的虚拟函数需要用大括号来定义,而不是在其名称末尾使用分号。我可以做基本的 C++,但继承、虚函数等不是我经常使用的东西。

#1 和 #2 定义虚拟函数 setTimeDate() 的方式有什么区别?

TouchGFX允许您为显示器创建“屏幕”。就像你的手机显示屏一样。打开它,有一个屏幕。如果您滑动或打开应用程序,则会看到不同的屏幕。

有两个类适用于所有屏幕(和)。项目中的每个屏幕都增加了两个类(和一个)。我在下面展示了类,但还有另一个......中没有定义虚函数...我还没有了解代码的那部分。我得到的错误是:modelmodelListenerPresenterViewprincipalScreenSecondScreenSecondScreen

./Application/User/gui/SecondScreenPresenter.o:(.rodata._ZTV21SecondScreenPresenter+0x28):undefined reference to `ModelListener::setTime(displayTime_t)'

osMessageQueueGetCount, osMessageQueueGet are part of [CMSIS-RTOS2](https://www.keil.com/pack/doc/CMSIS/RTOS2/html/group__CMSIS__RTOS__Message.html).

我只更改了类中的定义,错误就消失了。model

virtual void setTime(displayTime_t time);   // #1 error

virtual void setTime(displayTime_t time){}  // #2 correct
class ModelListener
{
    public:
        ModelListener() : model(0) {}

        virtual ~ModelListener() {}

        void bind(Model* m)
        {
            model = m;
        }

        virtual void setTimeDate(displayTimeDate_t nTimeDate){}

    protected:
        Model* model;

};
Model::Model() : modelListener(0), newTimeDate({0})
{

}

void Model::tick()
{
    if(osMessageQueueGetCount(qRTCtoUIHandle)>0)
    {
        if(osMessageQueueGet(qRTCtoUIHandle, &newTimeDate, 0, 0)==osOK)
        {
            modelListener->setTimeDate(newTimeDate);
        }
    }
}
class principalScreenPresenter : public touchgfx::Presenter, public ModelListener
{
    public:
        principalScreenPresenter(principalScreenView& v);
    
        /**
         * The activate function is called automatically when this screen is "switched in"
         * (ie. made active). Initialization logic can be placed here.
         */
        virtual void activate();
    
        /**
         * The deactivate function is called automatically when this screen is "switched out"
         * (ie. made inactive). Teardown functionality can be placed here.
         */
        virtual void deactivate();
    
        virtual ~principalScreenPresenter() {};
    
        virtual void setTimeDate(displayTimeDate_t nTimeDate);
    
    private:
        principalScreenPresenter();
    
        principalScreenView& view;
};
class principalScreenView : public principalScreenViewBase
{
    public:
        principalScreenView();
        virtual ~principalScreenView() {}
        virtual void setupScreen();
        virtual void tearDownScreen();

        virtual void setTimeDate(displayTimeDate_t nTimeDate);

    protected:

};

我正在关注 YouTube 视频来执行此操作,但是使用结构而不是视频中的 int,我以为我不小心将该函数复制/粘贴到不同的文件中。但经过几个小时的尝试,我发现这与屏幕交互有关。我自己无法弄清楚错误。

我在STM论坛上问过,有人给了我答案。我正在尝试了解有关解决方案的更多信息。我的 C++ 书(很旧)谈到了虚函数,但不是这个小区别。网上有很多东西,但我可以找到一个解释。

C++ 定义 虚函数 undefined-reference

评论

0赞 user17732522 7/1/2023
这里真的没有什么特别的。您可以以这种方式在类定义中定义任何成员函数,也可以像定义任何其他函数一样在类外部定义函数。 从来都不是定义,只是一个声明,无论是否存在。virtualvirtualvirtual void setTime(displayTime_t time);virtual
1赞 user17732522 7/1/2023
但是,也许您希望这些函数是纯虚函数,这意味着它们应该始终被派生类覆盖,因此不需要在基函数中定义?它的语法是虚函数特有的。virtualvirtual void setTime(displayTime_t time) = 0;

答:

1赞 Eugene 7/1/2023 #1

您的问题与虚函数无关,甚至不特定于 C++(这同样适用于 C)。

#1 和 #2 定义虚拟的方式有什么区别 函数 setTimeDate?

virtual void setTime(displayTime_t time);   // #1 error

virtual void setTime(displayTime_t time){}  // #2 correct

不同的是,#1 只是一个函数原型,而不是一个定义。它假定该函数是在其他地方定义的。如果未在任何地方提供函数定义,链接器将生成“未定义的引用”错误。

在 #2 中,您提供了一个函数体,它定义了一个空的(又名无操作)函数。{}

具体到函数,你可以指定它是纯的,即它没有任何实现,方法是在末尾添加:virtual=0

virtual void setTime(displayTime_t time) = 0;

但是,如果它包含在类中,则会使该类抽象化,即您不能创建此类的变量。它只能用作基类。

评论

1赞 Peter 7/1/2023
不是函数定义。整个构造是函数定义。是一个功能块(有时非正式地描述为函数体),是函数定义的重要组成部分。也可以(但可选)定义一个纯虚函数(例如,提供函数的基类版本,可以通过重写派生类中的函数来调用),并且这样的定义可以是内联的,也可以是非内联的。{}virtual void setTime(displayTime_t time){}{}