Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;有自己方法的对象?_C++_Oop - Fatal编程技术网

C++ C++;有自己方法的对象?

C++ C++;有自己方法的对象?,c++,oop,C++,Oop,对不起,这可能是个愚蠢的问题。我显然误解了面向对象编程的一些基本原理。我习惯了C和AM,现在尝试使用C++。 我在一个叫做Button的类中有一些按钮。每个按钮都有不同的功能。我想写的是这样的: Button button1; Button button2; ... void button1::onClick () { ... } void button2::onClick () { ... } 但这不起作用(“按钮1不是类、命名空间或枚举”-是的,我知道!)。我知道我可以为每

对不起,这可能是个愚蠢的问题。我显然误解了面向对象编程的一些基本原理。我习惯了C和AM,现在尝试使用C++。 我在一个叫做Button的类中有一些按钮。每个按钮都有不同的功能。我想写的是这样的:

Button button1;
Button button2;
...
void button1::onClick () {
    ...
}
void button2::onClick () {
    ...
}
但这不起作用(“按钮1不是类、命名空间或枚举”-是的,我知道!)。我知道我可以为每个按钮创建一个单独的类:

class button1_class : public Button {
public:
     void onclick () {
        ...
     }
} button1;
class button2_class : public Button {
     ...
}
但对我来说,当我确信一个班级只有一名成员时,我觉得这样做是不对的

我正在使用Agui,Allegro 5的GUI库

编辑

谢谢你的回复。虽然它们都是有用的,而且(我认为)都是有效的答案,但实际上还没有人说过“不,你不能拥有一个拥有自己独特方法的对象,因为……”

例如,如果object1的类型为ObjectClass,则不允许object1具有object1唯一的方法(成员函数),而只拥有定义为ObjectClass一部分的方法。是这样吗? 很抱歉,我没有包括我的实际用例。我更感兴趣的是,我只需要了解OOP,这样我就可以自己正确地完成它

编辑2
从更详细的回答来看,我认为lambda表达式是可能的,但这不是我想象的那样。再次感谢

如果按钮具有不同的功能,那么最好创建一个
BaseButton
类,在该类中将
onclick()
标记为
virtual
(或者将其设为纯虚拟,这将使
BaseButton
成为一个抽象类),然后从
BaseButton
派生其他按钮,确保在每个派生类中重写
onclick()
。然后,您需要通过引用或指向
BaseButton
的指针来使用按钮,这样您就可以实现所谓的“多态行为”

例如:

class BaseButton
{
    virtual void onclick() {/*implement here or declare pure virtual*/}
};

class RedButton: public BaseButton /* overrides only onclick */
{
    void onclick() override { /*specific implementation for Red Buttons */}
};

class ShinyRedButton: public RedButton /* overrides only onclick */
{
    void onclick() override { /*specific implementation for Shiny Red Buttons */}

};
然后像(C++14智能指针)一样使用它

std::unique_ptr bb=新ShinyRedButton;
bb->onclick();//将拾取“right”ShinyRedButton::onclick()`函数

> P>自然C++方式是按照VSOFTCO的解释,用虚拟和继承。p>

但是,如果你的<代码>按钮类已经需要所有的东西,而且按钮之间唯一的改变就是要执行的唯一的(TrWOWO)动作,你可能想考虑这个备选方案:

class Button {
    function<void()>  f; 
public: 
    Button(function<void()> mf) : f(mf) {}
    void onClick() { f();  }
};

使用std::函数是这里的关键。如果您的可调用函数(lambda、函数、成员函数)很大,则会听到虚拟调用,并可能会分配内存。这实现了您对单一类型执行不同回调的需求,而无需定义类继承。另外,使用统一初始化可以非常方便地使用lambda构造Button类,而无需手动创建构造函数

实例:

#包括
#包括
使用名称空间std;
结构按钮
{
函数OnClick;
};
int main()
{
矢量按钮=
{
{[]{printf(“Button0::OnClick()\n”);},
{[]{printf(“Button1::OnClick()\n”);},
{[]{printf(“Button2::OnClick()\n”);},
};
用于(自动和按钮:按钮)
button.OnClick();
}
您的系统支持信号系统,具有成员功能
addActionListener

这允许您从
agui::ActionListener
派生一个类,以执行一个或多个按钮的特定任务:

class SimpleActionListener : public agui::ActionListener
{
public:
    virtual void actionPerformed(const agui::ActionEvent &evt)
    {
        std::cout << "Button pushed" << std::endl;
    }
};

这是对的,如果每个按钮基本相同,但需要绑定不同的事件处理程序,那么为每个按钮实现一个新类型并不完全正确

相反,您的
按钮
类型将有一个成员函数,允许用户“附加”事件处理程序,并有一个成员函数来调用它

class Button
{
public:
    Button()
       : onClickHandler()
    {}

    void setOnClickHandler(std::function<void()> callback)
    {
       onClickHandler = callback;
    }

    friend class UI;

private:
    void onClick()
    {
       onClickHandler();
    }

    std::function<void()> onClickHandler;
};
class按钮
{
公众:
按钮()
:onClickHandler()
{}
void setOnClickHandler(std::函数回调)
{
onClickHandler=回调;
}
好友类用户界面;
私人:
void onClick()
{
onClickHandler();
}
std::函数onClickHandler;
};
然后您的用户执行以下操作:

void foo()
{
   std::cout << "Some buttons do this!\n";
}

Button btn;
btn.setOnClickHandler(foo);
void foo()
{

std::cout您可以通过多种方式实现这一点

  • 使用一个
    按钮
    类,其中按钮对象有一个指向被调用的方法的指针
    onClick
    。在C中,您可以使用回调来实现这一点,在C++中也可以这样做:

    class Button {
        using funType = void(void);
    public:
        Button(funType* callback) : function(callback) { }
        void onClick() { function(); }
    private:
        funType* function;
    };
    
    但是请注意,函数指针容易出错,编译器不能真正内联,通常应避免使用。此方法也适用于无捕获lambda

    Button red([] { std::cout << "Red button\n"; });
    Button green(&green_button_function);
    
    我在这里故意省略一些细节,例如参考资料。 然后,您可以通过以下方式使用带有回调和lambda的
    按钮
    类:

    auto green = make_button([] { std::cout << "Green button pressed!\n"; });
    auto red = make_button(&red_button_function);
    
    使用此方法需要从
    ButtonAction
    unique\u ptr
    s构建
    按钮
    s

    Button red(std::unique_ptr<ButtonAction>(new RedButtonAction));
    Button green(std::unique_ptr<ButtonAction>(new GreenButtonAction));
    
    按钮红色(std::unique_ptr(新的红色按钮操作));
    绿色按钮(标准::独特的(新的绿色按钮));
    

  • 一组类似的类,每个类只有一个同名的成员函数,但其他类的功能不同,这似乎不是一个好的设计。问题是什么?做得好!+1回答不错,我正要发布相同的想法。但是为什么在
    按钮1
    的lambda中都通过引用捕获?两者之间没有区别n“手动”使用成员初始化列表和您的方法创建构造函数。在代码生成方面,它们做同样的事情(您的代码还生成隐式默认构造函数)。这正是问题的关键。相同的结果,更少的代码。如果你能让编译器为你做,为什么还要做更多的工作?在我们讨论是否需要限制隐式定义构造函数/运算符的生成之前,需要更多的问题背景。一般来说,按钮有点复杂,我相信
    class Button {
        using funType = void(void);
    public:
        Button(funType* callback) : function(callback) { }
        void onClick() { function(); }
    private:
        funType* function;
    };
    
    Button red([] { std::cout << "Red button\n"; });
    Button green(&green_button_function);
    
    template <class Fun>
    class Button {
    public:
        Button(Fun f) : functor(f) { }
        void onClick() { functor(); }
    private:
        Fun functor;
    };
    
    template <class Fun>
    Button<Fun> make_button(Fun f) { return Button<Fun>(f); }
    
    auto green = make_button([] { std::cout << "Green button pressed!\n"; });
    auto red = make_button(&red_button_function);
    
    class ButtonAction {
    public:
        virtual void onClick() = 0;
    };
    
    class Button {
    public:
        Button(std::unique_ptr<ButtonAction> action) : 
            action_(std::move(action)) {}
        void onClick() { action_->onClick();  }
    private:
        std::unique_ptr<ButtonAction> action_;
    };
    
    class RedButtonAction : public ButtonAction {
        void onClick() override { red(); }
    };
    class GreenButtonAction : public ButtonAction {
        void onClick() override { green(); }
    };
    
    Button red(std::unique_ptr<ButtonAction>(new RedButtonAction));
    Button green(std::unique_ptr<ButtonAction>(new GreenButtonAction));