关于函数参数类型隐式转换与子类类型有关问题,小弟我与vs2003编译器的理解不同
关于函数参数类型隐式转换与子类类型问题,我与vs2003编译器的理解不同
先看下源代码,函数内容不用管,骗编译器的,只看接口。
编译环境:VS2003 7.1.3088
class A
{
};
class B
{
public:
operator A*() { return NULL; };
};
class C
{
public:
operator B() { B b; return b; };
};
class D : public A
{
};
class E
{
public:
operator D*() { return NULL; };
};
class F
{
public:
operator D() { D d; return d; };
};
void foo1(A* a) {};
void foo3(A a) {};
int main()
{
B b;
C c;
E e;
F f;
foo1(b); // 1
foo1(c); // 2
foo1(e); // 3
foo3(f); // 4
return 0;
}
首先,我知道的原则,编译器在匹配函数参数时,不会为你做2次隐式转换(记不清确切术语了,请原谅),因此,上面注释1的地方可以成功,注释2的地方会编译失败。这个没问题。
但是对于3和4,我就比较惊讶,特别是4。
对于3来说,存在隐式转换将e变成D*类型,但是foo1要求的是A*。 这个能编译通过,我姑且算作子类指针永远可以看成父类指针,因此不需要转换。
但是对于4来说,将f转换成D类型,居然就可以直接匹配A类型?
也许我对继承的理解有误?继承下来的子类,不必作任何转换就可以看作父类类型?这么说倒是也很合逻辑。。。
企盼达人解惑。
------解决方案--------------------
class A
{
public:
virtual void print() { cout < < "A::print() " < < endl; }
};
class B: public A
{
public:
virtual void print() { cout < < "B::print() " < < endl; }
};
void f(A a)
{
a.print(); // 调用 A::print()
}
int main()
{
B b;
f(b); // 这里传参时调用了(编译器提供的)拷贝构造函数
return 0;
}
如果要定义拷贝构造函数,比如上面类A
A::A(const A& a)
{
// 这里的a时一个指向基类的引用,当然a也可以指向子类(和指针一样),所以子类是可以直接用来构造基类的
// ...
}
------解决方案--------------------
去看《C++ Primer》3e P649
章节:对用户定义的转换序列划分等级
------解决方案--------------------
也许我对继承的理解有误?继承下来的子类,不必作任何转换就可以看作父类类型?
===========
可以这么认为,
这个转换其实是一个 对象截取,
总是可以从一个 子类对象中 截取出父类子对象的。
------解决方案--------------------
对于3来说,存在隐式转换将e变成D*类型,但是foo1要求的是A*。 这个能编译通过,我姑且算作子类指针永远可以看成父类指针,因此不需要转换。
---------
这个本来派生,多态就是这样,派生类指针永远是基类指针
struct base
{
int n1;
int n2;
int n3;
int n4;
};
struct derive : public base
{
};
void fun(base s)
{
}
int main(void)
{
derive d;
fun(d);
}
这个是能编过运行,所以你的 4 也就没问题
这并没有2次转换,而是直接把派生类截取到基类
看看asm就知道了
------解决方案--------------------
ISO C++ Standard (ISO14882) 2003.pdf里找的。
12.3 P192
At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single
value.
下面包含User-defined conversion的定义:
Type conversions of class objects can be specified by constructors and by conversion functions. These conversions
are called user-defined conversions and are used for implicit type conversions (clause 4), for
initialization (8.5), and for explicit type conversions (5.4, 5.2.9).
先看下源代码,函数内容不用管,骗编译器的,只看接口。
编译环境:VS2003 7.1.3088
class A
{
};
class B
{
public:
operator A*() { return NULL; };
};
class C
{
public:
operator B() { B b; return b; };
};
class D : public A
{
};
class E
{
public:
operator D*() { return NULL; };
};
class F
{
public:
operator D() { D d; return d; };
};
void foo1(A* a) {};
void foo3(A a) {};
int main()
{
B b;
C c;
E e;
F f;
foo1(b); // 1
foo1(c); // 2
foo1(e); // 3
foo3(f); // 4
return 0;
}
首先,我知道的原则,编译器在匹配函数参数时,不会为你做2次隐式转换(记不清确切术语了,请原谅),因此,上面注释1的地方可以成功,注释2的地方会编译失败。这个没问题。
但是对于3和4,我就比较惊讶,特别是4。
对于3来说,存在隐式转换将e变成D*类型,但是foo1要求的是A*。 这个能编译通过,我姑且算作子类指针永远可以看成父类指针,因此不需要转换。
但是对于4来说,将f转换成D类型,居然就可以直接匹配A类型?
也许我对继承的理解有误?继承下来的子类,不必作任何转换就可以看作父类类型?这么说倒是也很合逻辑。。。
企盼达人解惑。
------解决方案--------------------
class A
{
public:
virtual void print() { cout < < "A::print() " < < endl; }
};
class B: public A
{
public:
virtual void print() { cout < < "B::print() " < < endl; }
};
void f(A a)
{
a.print(); // 调用 A::print()
}
int main()
{
B b;
f(b); // 这里传参时调用了(编译器提供的)拷贝构造函数
return 0;
}
如果要定义拷贝构造函数,比如上面类A
A::A(const A& a)
{
// 这里的a时一个指向基类的引用,当然a也可以指向子类(和指针一样),所以子类是可以直接用来构造基类的
// ...
}
------解决方案--------------------
去看《C++ Primer》3e P649
章节:对用户定义的转换序列划分等级
------解决方案--------------------
也许我对继承的理解有误?继承下来的子类,不必作任何转换就可以看作父类类型?
===========
可以这么认为,
这个转换其实是一个 对象截取,
总是可以从一个 子类对象中 截取出父类子对象的。
------解决方案--------------------
对于3来说,存在隐式转换将e变成D*类型,但是foo1要求的是A*。 这个能编译通过,我姑且算作子类指针永远可以看成父类指针,因此不需要转换。
---------
这个本来派生,多态就是这样,派生类指针永远是基类指针
struct base
{
int n1;
int n2;
int n3;
int n4;
};
struct derive : public base
{
};
void fun(base s)
{
}
int main(void)
{
derive d;
fun(d);
}
这个是能编过运行,所以你的 4 也就没问题
这并没有2次转换,而是直接把派生类截取到基类
看看asm就知道了
------解决方案--------------------
ISO C++ Standard (ISO14882) 2003.pdf里找的。
12.3 P192
At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single
value.
下面包含User-defined conversion的定义:
Type conversions of class objects can be specified by constructors and by conversion functions. These conversions
are called user-defined conversions and are used for implicit type conversions (clause 4), for
initialization (8.5), and for explicit type conversions (5.4, 5.2.9).