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