在继承class中重新定义一个常量成员变量
Redefine a constant member variable in inherited class
假设我希望在父 class 中定义一个成员变量,并在继承的 class 中设置它的值。也许这些标识了 class 中可用的功能或子 class 的性质。例如:
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;
};
不言而喻,范围问题会阻止上述功能正常工作。但是,有没有办法让这项工作按预期进行?
因为变量是为了识别继承的classes的性质,所以我更喜欢它是const——如果它不是const并且只是在构造函数中重新定义就不会出现这个问题,所以据我所知。
在摆弄编译器以确保我的示例代码有意义时,我实际上遇到了一个事实,即我尝试定义常量的方式是特定于 C++11 的。这让我研究了以前的做法,我发现 this question,这间接地阐明了这个问题。
以这种方式定义变量应该通过让基 class 在其构造函数中采用以下形式的参数来完成:
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 被继承的 classes 重新定义。
为了证明我在评论中提出的观点,这里有一个我认为你正在尝试做的事情的例子(从评论中推导出来)。
我在同一个程序中提供了鸭子类型和多态解决方案,每个解决方案都有一个定时 运行。
我使用了 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
假设我希望在父 class 中定义一个成员变量,并在继承的 class 中设置它的值。也许这些标识了 class 中可用的功能或子 class 的性质。例如:
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;
};
不言而喻,范围问题会阻止上述功能正常工作。但是,有没有办法让这项工作按预期进行?
因为变量是为了识别继承的classes的性质,所以我更喜欢它是const——如果它不是const并且只是在构造函数中重新定义就不会出现这个问题,所以据我所知。
在摆弄编译器以确保我的示例代码有意义时,我实际上遇到了一个事实,即我尝试定义常量的方式是特定于 C++11 的。这让我研究了以前的做法,我发现 this question,这间接地阐明了这个问题。
以这种方式定义变量应该通过让基 class 在其构造函数中采用以下形式的参数来完成:
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 被继承的 classes 重新定义。
为了证明我在评论中提出的观点,这里有一个我认为你正在尝试做的事情的例子(从评论中推导出来)。
我在同一个程序中提供了鸭子类型和多态解决方案,每个解决方案都有一个定时 运行。
我使用了 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