我在C ++中有一个问题,我有
A
在下面的代码中。B
和C
。do_stuff_1
和do_stuff_2
。到目前为止,我的解决方案是混合模板和抽象类。目标是保持指向抽象类B
或C
的指针并调用do_stuff
。我的问题是
到目前为止,这是我的解决方案
#include <iostream>
#include <memory>
/* base virtual class */
class A {
public:
int a;
A(int a) : a(a) {}
virtual void do_stuff() = 0;
};
/* concrete implementations of do_stuf */
template<class T>
class do_stuff_1 : public T {
public:
using T::T;
void do_stuff(){
std::cout << "do_stuff_1 " << this->a << std::endl;
}
};
template<class T>
class do_stuff_2 : public T {
public:
using T::T;
void do_stuff(){
std::cout << "do_stuff_2 " << this->a + 1 << std::endl;
}
};
/* derived classes from A */
class B : public A {
public:
int b; // one member here but many more in my application
B(int a, int b): A(a), b(b) {}
};
class C : public A {
public:
std::string c; // one member here but many more in my application
C(int a, std::string c): A(a), c(c) {}
};
int main() {
std::unique_ptr<B> x;
x.reset(new do_stuff_1<B>(1, 1));
x->do_stuff();
std::cout << x->b << std::endl;
x.reset(new do_stuff_2<B>(1, 2));
x->do_stuff();
std::cout << x->b << std::endl;
std::unique_ptr<C> z;
z.reset(new do_stuff_1<C>(1, "Yo"));
z->do_stuff();
std::cout << z->c << std::endl;
z.reset(new do_stuff_2<C>(1, "Hello"));
z->do_stuff();
std::cout << z->c << std::endl;
return 0;
}
结果是
do_stuff_1 1
1
do_stuff_2 2
2
do_stuff_1 1
Yo
do_stuff_2 2
Hello
答案 0 :(得分:1)
你的解决方案似乎很好。它是一种编译时方法,您可以创建4个不同的对象。
主要缺点是:
do_stuff()
代码是否正确。 do_stuff_1
或do_stuff_2
。您应该至少在模板中使用override
以确保它覆盖虚函数。< / LI>
这是解决这些问题的一个小改进:
template<class T>
class do_stuff_2 : public T {
public:
using T::T;
void do_stuff() override {
static_assert (std::is_base_of<A, T>::value, "T should be derived from A");
std::cout << "do_stuff_2 " << this->a + 1 << std::endl;
}
};
顺便说一句,使用make_unique
会很好。
答案 1 :(得分:0)
对我来说看起来像某种政策,这可能看起来像:
#include <iostream>
#include <memory>
#include <type_traits>
struct AwayToDoTheStuff {
virtual void operator()(int a) = 0;
virtual ~AwayToDoTheStuff() {}
};
/* concrete implementations of do_stuf */
class HowToDoStuff1 : public AwayToDoTheStuff {
public:
void operator()(int a) override {
std::cout << "do_stuff_1 " << a << std::endl;
}
};
class HowToDoStuff2 : public AwayToDoTheStuff {
public:
void operator()(int a) override {
std::cout << "do_stuff_2 " << a + 1 << std::endl;
}
};
/* base virtual class */
template <class HowToDoStuff>
class A {
public:
int a;
A(int a) : a(a) {}
void do_stuff() {
static_assert(std::is_base_of<AwayToDoTheStuff, HowToDoStuff>::value);
HowToDoStuff()(a);
}
};
/* derived classes from A */
template <class HowToDoStuff>
class B : public A<HowToDoStuff> {
public:
int b; // one member here but many more in my application
B(int a, int b): A<HowToDoStuff>(a), b(b) {}
};
template <class HowToDoStuff>
class C : public A<HowToDoStuff> {
public:
std::string c; // one member here but many more in my application
C(int a, std::string c): A<HowToDoStuff>(a), c(c) {}
};
int main() {
B<HowToDoStuff1>(1, 1).do_stuff();
B<HowToDoStuff2>(1, 2).do_stuff();
C<HowToDoStuff1>(1, "Yo").do_stuff();
C<HowToDoStuff2>(1, "Hello").do_stuff();
return 0;
}
但我必须说这很难说一个解决方案是否与一个非常通用的例子匹配得很好。我希望它能在某些方面帮助你......
修改强>:
您似乎需要拥有一个公共基类,以便您可以将对象B和C传递给void f(A &a);
然后我的例子可以这样调整:
/* base virtual class */
class A {
public:
void do_stuff() = 0;
};
template <class HowToDoStuff>
class Policy_A : public A {
public:
int a;
A(int a) : a(a) {}
void do_stuff() override {
static_assert(std::is_base_of<AwayToDoTheStuff, HowToDoStuff>::value);
HowToDoStuff()(a);
}
};
/* derived classes from A */
template <class HowToDoStuff>
class B : public Policy_A<HowToDoStuff> {
public:
int b; // one member here but many more in my application
B(int a, int b): Policy_A<HowToDoStuff>(a), b(b) {}
};
template <class HowToDoStuff>
class C : public Policy_A<HowToDoStuff> {
public:
std::string c; // one member here but many more in my application
C(int a, std::string c): Policy_A<HowToDoStuff>(a), c(c) {}
};
这样就可以在不透明的A对象上调用do_stuff。
您也可以在创建时传递HowToDoStuff对象:
/* base virtual class */
class A {
std::unique_ptr<AwayToDoTheStuff> _stuffer;
public:
int a;
A(std::unique_ptr<AwayToDoTheStuff> stuffer, int a) : _stuffer(std::move(stuffer)), a(a) {}
void do_stuff() {
(*_stuffer)(a);
}
};
/* derived classes from A */
class B : public A {
public:
int b; // one member here but many more in my application
B(std::unique_ptr<AwayToDoTheStuff> &stuffer, int a, int b): A(std::move(stuffer), a), b(b) {}
};
class C : public A {
public:
std::string c; // one member here but many more in my application
C(std::unique_ptr<AwayToDoTheStuff> &stuffer, int a, std::string c): A(std::move(stuffer), a), c(c) {}
};
int main() {
auto stuffer1forB = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff1);
auto stuffer2forB = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff2);
B(stuffer1forB, 1, 1).do_stuff();
B(stuffer2forB, 1, 2).do_stuff();
auto stuffer1forC = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff1);
auto stuffer2forC = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff2);
C(stuffer1forC, 1, "Yo").do_stuff();
C(stuffer2forC, 1, "Hello").do_stuff();
return 0;
}