upcasting 的理解
来源:互联网 发布:linux sys gpio 编辑:程序博客网 时间:2024/06/03 16:47
什么叫“upcasting”?
从派生类到基类的转换在继承表中是往上走的,因此叫upcasting,其总是安全的,因为其将一个特定的对象转换为了一个更通用的对象。唯一的变化是其可能失去某些成员,但它至少还是个instrument,因此编译器不用显式的强制转换。
Upcasting和拷贝构造函数
当编译器为派生类自动生成拷贝构造函数时,其将自动调用基类的拷贝构造函数,然后是各个成员对象的拷贝构造函数。
//: C14:CopyConstructor.cpp
// Correctly creating the copy-constructor
#include <iostream>
using namespace std;
class Parent {
int i;
public:
Parent(int ii) : i(ii) {
cout << "Parent(int ii)/n";
}
Parent(const Parent& b) : i(b.i) {
cout << "Parent(const Parent&)/n";
}
Parent() : i(0) { cout << "Parent()/n"; }
friend ostream&
operator<<(ostream& os, const Parent& b) {
return os << "Parent: " << b.i << endl;
}
};
class Member {
int i;
public:
Member(int ii) : i(ii) {
cout << "Member(int ii)/n";
}
Member(const Member& m) : i(m.i) {
cout << "Member(const Member&)/n";
}
friend ostream&
operator<<(ostream& os, const Member& m) {
return os << "Member: " << m.i << endl;
}
};
class Child : public Parent {
int i;
Member m;
public:
Child(int ii) : Parent(ii), i(ii), m(ii) {
cout << "Child(int ii)/n";
}
friend ostream&
operator<<(ostream& os, const Child& c){
return os << (Parent&)c << c.m
<< "Child: " << c.i << endl;
}
};
int main() {
Child c(2);
cout << "calling copy-constructor: " << endl;
Child c2 = c; // Calls copy-constructor
cout << "values in c2:/n" << c2;
} ///:~
return os << (Parent&)c << c.m
Parent(int ii)
Member(int ii)
Child(int ii)
calling copy-constructor:
Parent(const Parent&)
Member(const Member&)
values in c2:
Parent: 2
Member: 2
Child: 2
当自己实现拷贝构造函数时,忘记了调用基类的拷贝构造函数,这时候编译器会调用默认的构造函数,因为对于C++来说必须确保任何对象初始化过。
Child(const Child& c) : i(c.i), m(c.m) {}
Parent(int ii)
Member(int ii)
Child(int ii)
calling copy-constructor:
Parent() //默认的无参构造函数
Member(const Member&)
values in c2:
Parent: 0
Member: 2
Child: 2
因此当自己实现拷贝构造函数时必须确保调用了基类的拷贝构造函数。如下:
Child(const Child& c)
: Parent(c), i(c.i), m(c.m) {
cout << "Child(Child&)/n";
}
这又是一个upcasting的例子,将child对象作为基类的引用参数传递给基类,因为child的引用将自动转换为parent的引用。
指针和引用的upcasting
除了在函数调用时编译器可以实现自动转换外,在进行指针或者引用赋值时也可以自动转换。和函数调用一样,这两种情况都不需要显式的强制转换。
Wind w;
Instrument* ip = &w; // Upcast
Instrument& ir = w; // Upcast
危机
在upcast的时候会失去类型信息,如下编译器只能将ip作为Instrument的指针来调用
Wind w;
Instrument* ip = &w;
ip->play(middleC);
此时调用的是基类的Instrument::play( )而非本意Wind::play( ).,这种问题可以通过面向对象的编程技术的第三个里程碑多态polymorphism来解决,在C++中是通过虚函数来实现的。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
采用多态技术是值传递和地址传递有很大的区别,因为地址大小总是一样的;传递派生类的地址和基类的地址是一样的,因为派生类中包含了基类。值传递时,派生对象将剥离只剩下基类部分。
//: C15:ObjectSlicing.cpp
#include <iostream>
#include <string>
using namespace std;
class Pet {
string pname;
public:
Pet(const string& name) : pname(name) {}
virtual string name() const { return pname; }
virtual string description() const {
return "This is " + pname;
}
};
class Dog : public Pet {
string favoriteActivity;
public:
Dog(const string& name, const string& activity)
: Pet(name), favoriteActivity(activity) {}
string description() const {
return Pet::name() + " likes to " +
favoriteActivity;
}
};
void describe(Pet p) { // Slices the object
cout << p.description() << endl;
}
int main() {
Pet p("Alfred");
Dog d("Fluffy", "sleep");
describe(p);
describe(d);
} ///:~
This is Alfred
This is Fluffy
两个原因:
首先,当调用describe时,只有Pet大小的东西在栈上分配释放,因此多余的部分将被剥离;
其次,因为是值传递,编译器知道具体的数据类型,将调用pet的拷贝构造函数,其将VPTR初始化为PET的VTABLE,然后将dog的基类部分拷贝至p中,因此p将变成完完全全的pet对象。
向上转换为基类对象是很少见的,应该尽量避免,若将description声明为纯虚函数,则编译器将禁止基类对象的值传递,因为抽象类不能够创建对象。这是纯虚函数的一个重要特性,其可以防止对象剥离。
- upcasting 的理解
- upcasting
- 指针和引用的upcasting
- JAVA基础复习(二)继承的一点细节:upcasting
- Talk About“Upcasting”
- upcasting and downcasting
- java upcasting downcasting
- [面向对象]为什么要upcasting?
- Talk About“Upcasting”[翻译后]
- java多态性---upcasting and downcasting
- think in java笔记 upcasting
- 在Java中使用Upcasting和Downcasting
- AxonFramework,事件向上转换(Event Upcasting)
- Java Upcasting 上溯造型 Downcasting -Java 学习笔记 (17)
- java向上转型 向下转型(upcasting downcasting)
- java中转型(upcasting)与动态绑定(dynamic binding)或者后期(late binding)细节
- java中转型(upcasting)与动态绑定(dynamic binding)或者后期(late binding)细节
- compler moves this pointer while Upcasting derived ojbect pointe to parent pointe by static_cast
- 利用素数表快速寻找 n 以内的所有素数
- 爱一个不爱你的人,就像在机场等一艘船
- 解说jquery的has()方法以及与find()方法以及filter()方法的区别
- spring整合struts,hibernate annotation(pool数据池,sqlserver2005数据库)
- Vim+cscope+ctags+tags阅读源代码
- upcasting 的理解
- 绝对路径和相对路径
- 递归求阶乘
- getopt_long
- C# DataGridView显示行号的两种方法
- 49个jQuery代码经典片段
- 四、在终端上 显示 文字 和 变量的值(二)
- Can't convert argument
- ubuntu64位安装Adobe Air