类型在语义上等效时,隐式转换非常有用.例如,假设两个库以相同的方式实现类型,但在不同的命名空间中.或者只是一种大多数相同的类型,除了一些语义糖在这里和那里.现在,您无法将一种类型传递给设计为使用另一种的函数(在其中一个库中),除非该函数是模板.如果不是,你必须以某种方式将一种类型转换为另一种类型.这应该是微不足道的(或者其他类型在后面都不是那么相同!)但是调用转换显然会使代码膨胀,而且函数调用几乎毫无意义.虽然这样的转换函数实际上可能会复制一些值,但它们从高级"程序员"的角度来看基本上什么都不做.
隐式转换构造函数和运算符显然可以提供帮助,但它们引入了耦合,因此其中一种类型必须知道另一种类型.通常,至少在处理库时,情况并非如此,因为其中一种类型的存在使另一种类型变得冗余.此外,您不能总是更改库.
现在我看到有关如何在用户代码中进行隐式转换的两个选项:
第一个是提供代理类型,它为所有涉及的类型实现转换操作符和转换构造函数(和赋值),并始终使用它.
第二个需要对库进行最小的更改,但允许很大的灵活性:为每个可以在外部选择启用的相关类型添加转换构造函数.
例如,对于类型A添加构造函数:
template <class T> A(
const T& src,
typename boost::enable_if<conversion_enabled<T,A>>::type* ignore=0
)
{
*this = convert(src);
}
Run Code Online (Sandbox Code Playgroud)
和一个模板
template <class X, class Y>
struct conversion_enabled : public boost::mpl::false_ {};
Run Code Online (Sandbox Code Playgroud)
默认情况下禁用隐式转换.
然后要启用两种类型之间的转换,请专门化模板:
template <> struct conversion_enabled<OtherA, A> : public boost::mpl::true_ {};
Run Code Online (Sandbox Code Playgroud)
并实现一个convert可以通过ADL找到的函数.
我个人更喜欢使用第二种变体,除非有强烈的反对意见.
现在回答实际问题:关联隐式转换类型的首选方法是什么?我的建议是好主意吗?两种方法都有任何缺点吗?允许这样的转换是危险的吗?如果库类实现者通常会提供第二种方法,那么它们的类型很可能会被软件复制,而这些软件很可能与它们一起使用(我在考虑使用3d渲染中间件,其中大多数软件包实现了3D向量).
C++附带了四个内置的强制转换.
static_castdynamic_castconst_castreinterpret_cast不要说皱眉头C (style*)cast.
另外,boost提供了一个lexical_cast,你还有其他有用的演员阵容吗?
在下面的例子中,为什么我不能简单地传递string给printFoo()?
#include <string>
#include <iostream>
using namespace std;
class Foo {
public:
Foo(const Foo &foo) : str(foo.str) {}
Foo(string str) : str(str) {}
string str;
};
void printFoo(Foo foo) {
cout << foo.str << endl;
}
int main() {
Foo foo("qux");
printFoo(foo); // OK
printFoo("qix"); // error: no matching function for call to 'printFoo'
return 0;
}
Run Code Online (Sandbox Code Playgroud)
无论出于何种原因,我都在脑海中自动确定并使用构造函数来构造对象.
为什么我不能这样做,但是我可以将char[n]常数传递给接受a的参数std::string,例如?
我有以下代码:
#include <iostream>
#include "boost/shared_ptr.hpp"
using boost::shared_ptr;
class Base {
public:
virtual ~Base() {}
virtual void print() = 0;
};
template <typename T>
class Child : public Base {
public:
virtual void print() {
std::cout << "in Child" << std::endl;
}
};
class GrandChild : public Child<int> {
public:
virtual void print() {
std::cout << "in GrandChild" << std::endl;
}
};
template <typename T>
void call_print(shared_ptr<Child<T> > a) {
a->print();
}
void call_base_print(shared_ptr<Base> a) {
a->print();
}
int main() { …Run Code Online (Sandbox Code Playgroud) 我想知道在c ++中是否有可能像在这个C#示例中那样实现相同的转换重载:
class A {
public static implicit operator A(string s) {
return new A();
}
public static implicit operator A(double d) {
return new A();
}
static void Main(string[] args) {
A a = "hello";
A b = 5.0;
}
}
Run Code Online (Sandbox Code Playgroud)
在C++中它应该是这样的:
#include <string>
using namespace std;
class A{
/*SOME CAST OVERLOADING GOES HERE*/
};
void main(){
A a = "hello";
A b = 5.0;
}
Run Code Online (Sandbox Code Playgroud)
你能帮助我如何使这个演员超载吗?
我想完全理解转换,即确保我知道函数调用何时会导致隐式转换,何时会导致编译错误.我已经知道,当且仅当有一种单一的方法将变量转换为以下列表中的两个步骤(按优先级排序)时,才能进行转换:
1. Exact match
2. Promotion
3. Conversion
4. User defined conversion
Run Code Online (Sandbox Code Playgroud)
其中,顺便我的理解是(你可以指正),是推广是原语转化成更大的原始类型,如短整型,浮点翻番,等等; 转换是基元之间的任何转换,不是促销,例如int到char等; 用户定义的转换是使用转换构造函数和转换运算符的类转换.现在,我也知道继承意味着和Is-A关系,这意味着派生类是基类,因此将派生类发送到期望引用基类的函数应该有效.结合上面的两个概念,我们应该得到以下我写的例子,应该工作:
class C {};
class D: public C
{
public:
D(int x){}
};
void f(C& c) {}
f(3);
Run Code Online (Sandbox Code Playgroud)
因为D可以从int转换为,而D是C.但是这个代码没有被编译.这是为什么?如何解决矛盾?你能否解释一下这个问题?谢谢!
我最近意识到我可以这样做:
void someFunc(const std::string &str)
{
//content
}
...
someFunc("Hello World"); //this works
Run Code Online (Sandbox Code Playgroud)
我想知道它是如何工作的以及为什么它有效.
谢谢