假设我希望在父类中定义成员变量,并在继承的类中设置其值。也许这些标识了类中可用的功能或子类的性质。例如:
class A
{
public:
inline int getX() { return x; }
protected:
const int x = 0;
};
class B : public A
{
protected:
const int x = 10;
};
class C : public A
{
protected:
const int x = 50;
};
不言而喻,范围问题将阻止上述工作正常进行。但是,有没有办法使这项工作按预期进行?
因为变量是为了识别继承类的本质,所以我更喜欢它是const - 如果它不是const而且只是在构造函数中重新定义,那么这个问题不会出现,据我所知。 / p>
答案 0 :(得分:4)
虽然摆弄编译器试图确保我的示例代码有意义,但实际上我发现我试图定义常量的方式是C ++ 11特定的。这让我开始研究它以前的方式,我找到this question,间接地阐明了这个问题。
以这种方式定义变量应该通过让基类在其构造函数中采用参数来完成,其形式为:
class A
{
public:
A( const int& type ) : x(type) {}
inline int getX() { return x; }
protected:
const int x;
};
class B : public A
{
public:
B() : A(10) {}
};
class C : public A
{
public:
C() : A(50) {}
};
这将按预期工作,并允许继承类重新定义常量x。
答案 1 :(得分:0)
为了证明我在评论中提出的观点,这里有一个我认为你想做的事情的例子(从评论中推断出来)。
我在同一个程序中提供了duck-typed和polymorphic两个解决方案,每个解决方案都有一个定时运行。
我使用1000万个样本来消除内存缓存噪音。
您会注意到多态解决方案的运行时间明显少于鸭型解决方案的运行时间。
#ifdef _WIN32
#include <Windows.h>
double get_cpu_time(){
FILETIME a,b,c,d;
if (GetProcessTimes(GetCurrentProcess(),&a,&b,&c,&d) != 0){
// Returns total user time.
// Can be tweaked to include kernel times as well.
return
(double)(d.dwLowDateTime |
((unsigned long long)d.dwHighDateTime << 32)) * 0.0000001;
}else{
// Handle error
return 0;
}
}
#else
#include <sys/time.h>
inline double get_cpu_time() noexcept {
return (double)clock() / CLOCKS_PER_SEC;
}
#endif
#include <iostream>
#include <vector>
#include <memory>
struct A
{
A(bool copy_) : copy{copy_} {}
virtual ~A() = default;
const bool copy = false;
};
struct RealA : public A
{
RealA() : A { false } {}
};
struct CopyA : public A
{
CopyA() : A { true } {}
};
// A Thing holder will hold any object which has an interface supports do_something_to(T& thing)
struct AHolder {
template<class Thing>
AHolder(std::unique_ptr<Thing> ptr)
: _ptr { std::move(ptr) }
{
}
template<class Thing, class...Args>
static AHolder construct(Args&&...args)
{
return AHolder { std::make_unique<model<Thing>>(std::forward<Args>(args)...) };
}
void do_something() const {
_ptr->do_something();
}
private:
struct concept {
virtual ~concept() = default;
virtual void do_something() = 0;
};
template<class Thing> struct model : concept {
template<class...Args>
model(Args&&...args) : _thing { std::forward<Args>(args)... } {}
private:
void do_something() override {
do_something_to(_thing);
}
Thing _thing;
};
std::unique_ptr<concept> _ptr;
};
using namespace std;
size_t copies_processed = 0;
size_t reals_processed = 0;
void do_something_to(const CopyA&)
{
// simulate work
++copies_processed;
}
void do_something_to(const RealA&)
{
// simulate work
++reals_processed;
}
int main(int argc, char **argv) {
std::vector<std::unique_ptr<A>> duck_typing;
std::vector<AHolder> polymorphic;
constexpr size_t samples = 10000000;
for (size_t i = 0 ; i < samples ; ++i) {
if (i % 2) {
duck_typing.push_back(make_unique<RealA>());
polymorphic.emplace_back(AHolder::construct<RealA>());
}
else {
duck_typing.push_back(make_unique<CopyA>());
polymorphic.emplace_back(AHolder::construct<CopyA>());
}
}
auto duck_start = get_cpu_time();
// nasty duck-typing solution
for (const auto& ptr : duck_typing) {
if (ptr->copy) {
do_something_to(*(static_cast<CopyA*>(ptr.get())));
}
else {
do_something_to(*(static_cast<RealA*>(ptr.get())));
}
}
auto duck_stop = get_cpu_time();
auto poly_start = get_cpu_time();
for (const auto& a_like : polymorphic) {
a_like.do_something();
}
auto poly_stop = get_cpu_time();
cout << "duck typing : " << duck_stop - duck_start << endl;
cout << "polymorphic : " << poly_stop - poly_start << endl;
cout << "copies processed : " << copies_processed << endl;
cout << "reals processed : " << reals_processed << endl;
return 0;
}
示例输出:
duck typing : 0.162985
polymorphic : 0.137561
copies processed : 10000000
reals processed : 10000000