#include
using namespace std;
class A {
public:
A(int a_parameters);
void display();
int get_a();
private:
int a;
};
A::A(int a_parameters) : a(a_parameters) {}
void A::display() { cout << "a:" << a << endl; }
int A::get_a() { return this->a; }
class B : public A {
public:
B(int a_parameters, int b_parameters);
void display();
private:
int b;
};
B::B(int a_parameters, int b_parameters) : A(a_parameters), b(b_parameters) {}
void B::display() { cout << "a:" << get_a() << ":b:" << b << endl; }
int main() {
system("chcp 65001");
cout << "基类和派生类初始化" << endl;
A a(3);
B b(5, 6);
a.display();
b.display();
cout << "--------------------" << endl;
cout << "B向上转型将对象的值赋给A" << endl;
a = b;
a.display();
b.display();
return 0;
}
输出:
Active code page: 65001
基类和派生类初始化
a:3
a:5:b:6
--------------------
B向上转型将对象的值赋给A
a:5
a:5:b:6
赋值是将已有的数据写入分配好的内存中,对象的内存只包含了成员变量,所以对象之间的赋值是成员变量的赋值。成员函数不存在赋值。对象之间的赋值不会影响成员函数,也不会影响this指针。上述程序中,虽然将b对象赋值给了a,实际上是将b中覆盖a成员变量的值重新赋值给了a中的成员变量,对于a.display()还是调用的a中定义的成员函数,并且this指针指向的还是对象a。
只能通过派生类赋值给基类,而不能够使用基类赋值派生类,因为派生类继承自基类,基类中非私有属性的成员变量在派生类中也存在,但是派生类会新增成员变量,在基类中并不存在,就无法将基类对象赋值给派生类对象。同理,同一基类的不同派生类中的对象之间也无法相互赋值。
#include
using namespace std;
class A {
public:
A(int a_parameters);
void display();
int get_a();
private:
int a;
};
A::A(int a_parameters) : a(a_parameters) { cout << "A constructed is created" << endl; }
void A::display() { cout << "a:" << a << endl; }
int A::get_a() { return this->a; }
class B : public A {
public:
B(int a_parameters, int b_parameters);
void display();
int get_b();
private:
int b;
};
B::B(int a_parameters, int b_parameters) : A(a_parameters), b(b_parameters) {
cout << "B constructed is created" << endl;
}
void B::display() { cout << "b_a:" << get_a() << "b_b:" << get_b() << endl; }
int B::get_b() { return this->b; }
class C {
public:
C(int c_parameters);
void display();
int get_c();
private:
int c;
};
C::C(int c_parameters) : c(c_parameters) { cout << "C constructed is created" << endl; }
void C::display() { cout << "c:" << c << endl; }
int C::get_c() { return this->c; }
class D : public B, public C {
public:
D(int a_parameters, int b_parameters, int c_parameters, int d_parameters);
void display();
int get_d();
private:
int d;
};
D::D(int a_parameters, int b_parameters, int c_parameters, int d_parameters) : B(a_parameters, b_parameters),
C(c_parameters) {
cout << "D constructed is created" << endl;
}
void D::display() { cout << "a:" << get_a() << ":b:" << get_b() << ":c" << get_c() << ":d:" << get_d() << endl; }
int D::get_d() { return this->d; }
int main() {
A *pa = new A(1);
B *pb = new B(2, 3);
C *pc = new C(5);
D *pd = new D(6, 7, 8, 9);
pa = pd;
pa->display();
pb = pd;
pb->display();
pc = pd;
pc->display();
cout << "pa=" << pa << endl;
cout << "pb=" << pb << endl;
cout << "pc=" << pc << endl;
cout << "pd=" << pd << endl;
return 0;
}
输出:
A constructed is created
A constructed is created
B constructed is created
C constructed is created
A constructed is created
B constructed is created
C constructed is created
D constructed is created
a:6
b_a:6b_b:7
c:8
pa=0x6d1ae0
pb=0x6d1ae0
pc=0x6d1ae8
pd=0x6d1ae0
通过上述程序发现,尽管将最终派生类D的对象指针pd指向了间接基类A,基类B和基类C,但是pa,pb,pc指向了pd后,却不能调用派生类D的成员函数,只能调用D的成员变量,因此就出现了基类A的指针pa指向pd后,仍然调用的是A的display(),pb,pc同理。一句话总结就是C++通过指针来访问成员变量,通过指针的类型来访问成员函数。
从上述结果中发现,pa,pb,pd指向的地址一致,但是pc指向的地址却比三个指针指向的地址都大,这是因为虽然赋值是将一个变量的值给另一个变量,但是赋值前编辑器可能会对现有的值进行处理,比如float变量赋值给int变量,就会舍弃小数部分,这样等式左右两边的值就不相等。将基类指针指向派生类指针的时候,编译器可能会在赋值前进行处理。我们知道,对象的指针必须要指向对象的起始位置。例如上述程序,基类A和B,他们对象的起始地址和D对象的起始地址是一样的,所以他们指向的内存都是一块内存。而C类对象和D类对象的起始位置有一定的偏移,当pc指向pd时,要算上这个偏移,这样pc才能指向C类对象的起始位置,这样就存在了上述中赋值前编译器对值进行了处理,这样就导致了pc指向的地址和其他三个指针指向的地址不一样的情况。
和基类指针指向派生类指针一样,只引用了派生类的成员变量,而不能引用派生类的成员函数。修改上述main()代码
int main() {
D d(1, 2, 3, 5);
A &a = d;
B &b = d;
C &c = d;
a.display();
b.display();
c.display();
cout << "a_address:" << &a << endl;
cout << "b_address:" << &b << endl;
cout << "c_address:" << &c << endl;
cout << "d_address:" << &d << endl;
return 0;
}
输出:
A constructed is created
B constructed is created
C constructed is created
D constructed is created
a:1
b_a:1b_b:2
c:3
a_address:0x63fdf0
b_address:0x63fdf0
c_address:0x63fdf8
d_address:0x63fdf0
引用和指针的表现之所以如此类似,是因为引用和指针并没有本质上的区别,引用仅仅是对指针进行了简单封装。