c++ class 设计、基础 class 继承或外观设计模式
c++ class design, base class inheritance, or facade design pattern
我有一个愚蠢的 C++ 设计问题。有没有办法让一个 class 与多个 class 中的方法具有相同的方法名称(因此,相同的 API)?
我目前的情况是我有classes
struct A
{
void foo() { std::cout << "A::foo" << std::endl;}
void boo() { std::cout << "A::boo" << std::endl;}
};
struct B
{
void moo() { std::cout << "B::moo" << std::endl;}
void goo() { std::cout << "A::goo" << std::endl;}
};
.... imagine possibly more
我真正想要的是另一个 class 作为这些功能的接口。我可能会误解为 外观设计模式 一个简单的接口,它隐藏了上面实例化 classes 的复杂性,但仍然使用它们相同的接口。
struct C
{
void foo() { ... }
void boo() { ... }
void moo() { ... }
void goo() { ... }
};
对于上面显示的少数方法,这可以通过声明结构 A 和 B 或将它们作为参数传递给结构 C 并在 C 中调用 A 和 B 的方法来实现,但如果 A 有 40 个方法,则这是不切实际的B有30个方法。在 C 中重新声明 70 个同名方法来调用 A 和 B 的底层方法,如果我能做得更好,这似乎是无缘无故的大量冗余。
我想到了第二种使用base的方案class
struct base
{
void foo() { }
void boo() { }
void moo() { }
void goo() { }
};
struct A : public base
{
void foo() { std::cout << "A::foo" << std::endl;}
void boo() { std::cout << "A::boo" << std::endl;}
};
struct B : public base
{
void moo() { std::cout << "B::moo" << std::endl;}
void goo() { std::cout << "A::goo" << std::endl;}
};
尝试使用具有所有函数定义的 shared_ptr。例如
std::shared_ptr<base> l_var;
l_var->foo();
l_var->boo();
l_var->moo();
l_var->goo();
这仍然不能完全满足我的要求,因为一半的方法是在结构 A 中定义的,而另一半是在结构 B 中定义的。
我想知道多重继承是否可以解决问题,但在学校我听说进行多重继承是不好的做法(调试很难?)
有什么想法或建议吗?基本上它更容易管理结构 A 和 B(等等,因为它是自己的 class 用于抽象目的)。但是希望在某种包装器中以某种方式调用他们的方法的灵活性,其中这种复杂性对用户隐藏。
使用虚拟多重继承。
的原因
it's bad practice to do multiple inheritance
是因为直接会导致模棱两可的调用或者冗余数据,所以可以用virtual inheritance来避免
学习 C++ 如何实现 iostream
我想会有很大帮助。
一个Bridge Design Pattern
会在这里大放异彩。通过将抽象与其实现分离,许多派生 类 可以单独使用这些实现。
struct base {
protected:
struct impl;
unique_ptr<impl> _impl;
};
struct base::impl {
void foo() {}
void bar() {}
};
struct A :public base {
void foo() { _impl->foo(); }
};
struct B:public base {
void foo() { _impl->foo(); }
void bar() { _impl->bar(); }
};
已编辑(例如实施)
#include <memory>
#include <iostream>
using namespace std;
struct base {
base();
protected:
struct impl;
unique_ptr<impl> _impl;
};
struct base::impl {
void foo() { cout << " foo\n"; }
void bar() { cout << " bar\n"; }
void moo() { cout << " moo\n"; }
void goo() { cout << " goo\n"; }
};
base::base():_impl(new impl()) {}
struct A :public base {
A():base() { }
void foo() { _impl->foo(); }
};
struct B:public base {
B() :base() { }
void foo() { _impl->foo(); }
void bar() { _impl->bar(); }
};
struct C :public base {
C() :base() { }
void foo() { _impl->foo(); }
void bar() { _impl->bar(); }
void moo() { _impl->moo(); }
void goo() { _impl->goo(); }
};
int main()
{
B b;
b.foo();
C c1;
c1.foo();
c1.bar();
c1.moo();
c1.goo();
return 0;
}
我认为
Redeclaring 70 methods with the same name in C to call the underlying
methods of A and B
是正确的道路。
在这种情况下很容易使用多重继承来避免编写传递代码,但我认为这通常是一个错误。更喜欢组合而不是继承。
我会质疑您的用户是否真的想用 70 个方法处理一个接口,但如果那真的是您想要的,那么我不明白为什么 "impractical" 将代码写在 [=11] 中=]:
class C {
A a;
B b;
public:
void foo() { return a.foo(); }
void boo() { return a.boo(); }
void moo() { return b.moo(); }
void goo() { return b.goo(); }
// ...
};
这样做的好处是,以后可以很容易地改变主意,将A
和B
换成别的东西,而不需要改变C
的界面。
您可以通过 using the PIMPL idiom or by splitting C
将 C
的实现进一步隐藏到抽象基础 class C
和实现 CImpl
中.
我支持 Chris Drew 的回答:与组合相比,不仅多重 iharitance 不好,任何 inharitance 都不好。
Fascade 模式的目的是隐藏复杂性。例如,假设您的 类 A 和 B 有 40 种和 30 种方法,Fascade 将公开其中大约 10 种——用户需要的那些。这样就避免了"if A has 40 methods and 30 has methods" then you have a big problem – n.m.
的问题
顺便说一句,我喜欢你使用 struct{}
而不是 class{public:}
的方式。这是颇有争议的,普遍的共识是it constitutes bad form,但stl
做到了,我也做到了。
回到问题。如果真的需要公开所有 70 个方法 (!!),我会采用更 pythonistic 的方法:
struct Iface
{
A _a;
B _b;
};
如果您设法使字段 const
,事情会变得更糟。第三次 - 你可能违反了那些大 类.
的 SRP
我有一个愚蠢的 C++ 设计问题。有没有办法让一个 class 与多个 class 中的方法具有相同的方法名称(因此,相同的 API)?
我目前的情况是我有classes
struct A
{
void foo() { std::cout << "A::foo" << std::endl;}
void boo() { std::cout << "A::boo" << std::endl;}
};
struct B
{
void moo() { std::cout << "B::moo" << std::endl;}
void goo() { std::cout << "A::goo" << std::endl;}
};
.... imagine possibly more
我真正想要的是另一个 class 作为这些功能的接口。我可能会误解为 外观设计模式 一个简单的接口,它隐藏了上面实例化 classes 的复杂性,但仍然使用它们相同的接口。
struct C
{
void foo() { ... }
void boo() { ... }
void moo() { ... }
void goo() { ... }
};
对于上面显示的少数方法,这可以通过声明结构 A 和 B 或将它们作为参数传递给结构 C 并在 C 中调用 A 和 B 的方法来实现,但如果 A 有 40 个方法,则这是不切实际的B有30个方法。在 C 中重新声明 70 个同名方法来调用 A 和 B 的底层方法,如果我能做得更好,这似乎是无缘无故的大量冗余。
我想到了第二种使用base的方案class
struct base
{
void foo() { }
void boo() { }
void moo() { }
void goo() { }
};
struct A : public base
{
void foo() { std::cout << "A::foo" << std::endl;}
void boo() { std::cout << "A::boo" << std::endl;}
};
struct B : public base
{
void moo() { std::cout << "B::moo" << std::endl;}
void goo() { std::cout << "A::goo" << std::endl;}
};
尝试使用具有所有函数定义的 shared_ptr。例如
std::shared_ptr<base> l_var;
l_var->foo();
l_var->boo();
l_var->moo();
l_var->goo();
这仍然不能完全满足我的要求,因为一半的方法是在结构 A 中定义的,而另一半是在结构 B 中定义的。
我想知道多重继承是否可以解决问题,但在学校我听说进行多重继承是不好的做法(调试很难?)
有什么想法或建议吗?基本上它更容易管理结构 A 和 B(等等,因为它是自己的 class 用于抽象目的)。但是希望在某种包装器中以某种方式调用他们的方法的灵活性,其中这种复杂性对用户隐藏。
使用虚拟多重继承。
的原因it's bad practice to do multiple inheritance
是因为直接会导致模棱两可的调用或者冗余数据,所以可以用virtual inheritance来避免
学习 C++ 如何实现 iostream
我想会有很大帮助。
一个Bridge Design Pattern
会在这里大放异彩。通过将抽象与其实现分离,许多派生 类 可以单独使用这些实现。
struct base {
protected:
struct impl;
unique_ptr<impl> _impl;
};
struct base::impl {
void foo() {}
void bar() {}
};
struct A :public base {
void foo() { _impl->foo(); }
};
struct B:public base {
void foo() { _impl->foo(); }
void bar() { _impl->bar(); }
};
已编辑(例如实施)
#include <memory>
#include <iostream>
using namespace std;
struct base {
base();
protected:
struct impl;
unique_ptr<impl> _impl;
};
struct base::impl {
void foo() { cout << " foo\n"; }
void bar() { cout << " bar\n"; }
void moo() { cout << " moo\n"; }
void goo() { cout << " goo\n"; }
};
base::base():_impl(new impl()) {}
struct A :public base {
A():base() { }
void foo() { _impl->foo(); }
};
struct B:public base {
B() :base() { }
void foo() { _impl->foo(); }
void bar() { _impl->bar(); }
};
struct C :public base {
C() :base() { }
void foo() { _impl->foo(); }
void bar() { _impl->bar(); }
void moo() { _impl->moo(); }
void goo() { _impl->goo(); }
};
int main()
{
B b;
b.foo();
C c1;
c1.foo();
c1.bar();
c1.moo();
c1.goo();
return 0;
}
我认为
Redeclaring 70 methods with the same name in C to call the underlying methods of A and B
是正确的道路。
在这种情况下很容易使用多重继承来避免编写传递代码,但我认为这通常是一个错误。更喜欢组合而不是继承。
我会质疑您的用户是否真的想用 70 个方法处理一个接口,但如果那真的是您想要的,那么我不明白为什么 "impractical" 将代码写在 [=11] 中=]:
class C {
A a;
B b;
public:
void foo() { return a.foo(); }
void boo() { return a.boo(); }
void moo() { return b.moo(); }
void goo() { return b.goo(); }
// ...
};
这样做的好处是,以后可以很容易地改变主意,将A
和B
换成别的东西,而不需要改变C
的界面。
您可以通过 using the PIMPL idiom or by splitting C
将 C
的实现进一步隐藏到抽象基础 class C
和实现 CImpl
中.
我支持 Chris Drew 的回答:与组合相比,不仅多重 iharitance 不好,任何 inharitance 都不好。
Fascade 模式的目的是隐藏复杂性。例如,假设您的 类 A 和 B 有 40 种和 30 种方法,Fascade 将公开其中大约 10 种——用户需要的那些。这样就避免了"if A has 40 methods and 30 has methods" then you have a big problem – n.m.
顺便说一句,我喜欢你使用 struct{}
而不是 class{public:}
的方式。这是颇有争议的,普遍的共识是it constitutes bad form,但stl
做到了,我也做到了。
回到问题。如果真的需要公开所有 70 个方法 (!!),我会采用更 pythonistic 的方法:
struct Iface
{
A _a;
B _b;
};
如果您设法使字段 const
,事情会变得更糟。第三次 - 你可能违反了那些大 类.