是否可以阻止引用的向上转换
Is it possible to block up-casting of references?
考虑一个用例:
- 你有一个可复制的类
Base
,你并不真正关心它会发生什么。 - 从它公开继承是一个
Derived
类,它不应该转换为Base
。一点也不。甚至没有对它的引用,对Base
的引用,换句话说,隐式绑定应该是非法的:Derived& -> Base&
。
注意:Derived
类是可复制的,只是它的内部不应该被放入常规的Base
对象中。由于可以直接禁止Derived
初始化Base
,因此问题仍然是是否可以禁止编译绕过它:Derived& -> Base& -> Base
.
假设static_cast
,指针不是问题 - 只是函数调用中的自动绑定。
下面是显示问题的基本示例:
#include <iostream>
using namespace std;
class Derived;
class Base
{
public:
Base(int var)
: m_var(var)
{
std::cout << "Base default ctor with value: " << m_var << std::endl;
}
Base& operator=(const Derived&) = delete;
Base& operator=(Derived&&) = delete;
Base(const Derived&) = delete;
Base(Derived&&) = delete;
int m_var;
};
class Derived : public Base
{
public:
Derived(int var)
: Base(var)
{
std::cout << "Derived default ctor with value: " << m_var << std::endl;
}
Base unprotect() const
{
std::cout << "Derived unprotected with value: " << m_var << std::endl;
return Base(m_var);
}
};
void foo(Base& base)
{
std::cout << "foo with value: " << base.m_var << std::endl;
// Base b2 = base; // just copied Derived, goal is to prohibit it!
}
int main()
{
Base b1(1);
foo(b1);
Derived d1(2);
foo(d1); // is it at all possible to disallow implicit Derived& -> Base&?
// rationale is to require explicit: Base& Dervied::getBaseRef()
// Base b2 = d1; // illegal: error: use of deleted function 'Base::Base(const Derived&)'
return 0;
}
从中公开继承是一个派生类,它不应该转换为 Base。一点也不。
从OOP设计的角度来看,这两件事几乎是矛盾的。我认为语言中没有办法防止将派生对象视为公共基础(通过引用的隐式转换)。
您可以非公开地继承Base
。
这也将防止显式转换 - 您仍然希望能够这样做。但仅限于类的范围之外。您可以改为提供一个成员来访问基本实例:
class Derived : Base
{
public:
// ...
Base& base() {
return *this;
}
};
现在,您可以将这些显式强制转换替换为对 Derived::base
的调用,这仍然是允许的,而隐式转换则不允许。
Derived d;
Base& b = d; // (implicit) conversion fails
Base& b = d.base(); // this works
您可能还希望实现该函数的const
版本。我将把这作为一项练习。
我的标准方法是使用私有继承,然后用 using
解除所有想要的方法、构造函数和运算符。
class Derived : private Base {
public :
using Base::Base;
using Base::some_base_method;
}
int main(){
Derived d1(2);
d1.some_base_method();
}
无论糟糕还是更糟,这也使得许多未来通过 Derived 的公共接口无法添加到 Base 中。它也适用于包括 CRTP 在内的模板。
由于您没有继承替换(您明确表示不希望将派生的外观用作基础),因此我假设您继承了一个实现。在这种情况下,答案很明确:根据您的确切需求继承private
或可能protected
。这完全禁止所有此类转换为基类,同时仍允许你的孩子访问基类的实现。
如果需要公开一个或两个基成员,则始终可以将它们using
派生类中。
相关文章:
- 强制转换为引用类型
- 如何将 int 引用安全地转换为长引用?
- C 样式转换引用
- 将通用引用强制转换为可调用的 void 指针,反之亦然
- 隐式重新解释引用时强制转换,没有警告/错误
- 右值引用转换后的地址更改
- 通过引用传递参数时C++类型转换
- 为什么我需要在转换构造函数上引用 this->?
- 枚举类的 C 样式强制转换到基础类型 char 的引用
- 转换指针引用的字符串
- 隐式可转换参数,但属于引用类型
- 转换引用对象的边界框?
- C++将引用转换为指针?
- C++ 引用是否在需要时隐式转换为值?
- 如果可能的话,C++总是更喜欢右值引用转换运算符而不是常量左值引用吗?
- 返回对常量结构(指针类型)成员的引用:明显的左值到右值转换
- 从基类的共享指针向下转换到派生类的引用
- 为什么 const 允许在参数中隐式转换引用
- 与强制类型转换指针相比,在dynamic_cast中使用强制类型转换引用
- 动态强制转换引用和自动转换