c++学习笔记,dynamic_cast,类的空指针问题,基类和派生类类型转换,(向上转换、向下转换)

1,基类和派生类的转换

1.1,定义两个有虚函数的基类,一个派生类实现这两个基类的虚函数

#include <iostream>

class A {
	public:
		virtual void fun_a() = 0;
};
class B {
	public:
		virtual void fun_b() = 0;
};

class C :public A, public B{
	public:
		void fun_a() override final {
			std::cout << "fun_a" << std::endl;
		}
		void fun_b() override final {
			std::cout << "fun_b" << std::endl;
		}
};

1.2,向下转型(即用基类指针指向派生类类型)

class D {
	private:
		A *m_a;
		B *m_b;
	public:
		void fun(C *pC) {
			//C派生类指针指向C派生类对象
			m_a = pC;//从派生类C转换出基类A的部分
			//m_a =  dynamic_cast<A*>(pC);//没有必要
			m_a->fun_a();
			m_b = pC;//从派生类C转换出基类B的部分
			//m_b =  dynamic_cast<B*>(pC);//没有必要
			m_b->fun_b();
		}
};

int main() {
	C c;
	D d;
	d.fun(&c);
	return 0;
}

1.3,向下转型(当基类指针指向基类类型时,需要注意)

class D {
	private:
		A *m_a;
		B *m_b;
	public:
		void fun(A *pA) {
			//A基类指针指向C派生类对象
			m_a = pA;//从A基类指针指向的C派生类转换出A基类的部分
			//m_a =  dynamic_cast<A*>(pC);//没有必要
			m_a->fun_a();
			//m_b = pA;//B基类类型指针无法指向A基类类型指针指向的C派生类
			m_b =  dynamic_cast<B*>(pA);//动态将A基类类型指针指向B基类类型(都指向C派生类对象)
			m_b->fun_b();
		}
};

int main() {
	C c;
	D d;
	d.fun(&c);
	return 0;
}

2,类的空指针问题

类中的函数被编译器静态编译了,所有非虚函数都可以调用,因为函数地址在编译期间已经确定。我们知道,类中的成员函数都是通过this指针调用成员变量的,编译器会将this指针作为默认参数传给类成员函数的,如myclass.function(int a,int b) --> function(&myclass,int a,int b)
编译后,成员函数传入了空的this指针,没有调用this指针则不出错,而后者调用了就会出错。调用成员函数的时候,函数地址是编译期间确定的,成员函数不通过对象指针(也即当前的p指针)去调用,对象指针仅仅作为参数传入函数然后去调用成员变量。
那如果是虚函数呢,因为虚函数要通过this指针计算vptr,然后找到vtable,然后dispatch。因为this指针为空,所以在找vtable时候就会coredump了。总之这类情况下,一切调用了this指针的函数都会出错,而完全不调用this指针的成员函数则没问题。

2.1,定义一个有数据成员的类,一个成员函数访问数据成员,一个不访问

#include <iostream>

class A {
	private:
		int m_data;
	public:
		virtual void fun_a(){
			std::cout << "A fun_a" << std::endl;
		}
		void print(){
			std::cout << "A data:" << m_data << std::endl;
		}
};
class C :public A{
	public:
		void fun_a() override final {
			std::cout << "C fun_a" << std::endl;
		}
};

2.2,类的空指针可以操作不访问类成员变量的类成员函数

int main() {
	C *pC;
	//C *pC=nullptr;//效果和C *pC一样都是空的类指针
	pC->fun_a();
	return 0;
}

在这里插入图片描述

2.2,类的空指针不可以操作访问类成员变量的类成员函数

int main() {
	//C *pC;
	C *pC=nullptr;
	pC->fun_a(); 
	pC->print();
	return 0;
}

在这里插入图片描述

int main() {
	C c;
	C *pC= &c;
	pC->fun_a(); 
	pC->print();
	return 0;
}

在这里插入图片描述

3,基类和派生类转化深入

3.1,定义基类和派生类

#include <iostream>
#include <sstream>

class A {
	private:
		int m_data_a = 1;
	public:
		virtual void fun_a(){
			std::cout << "A fun_a:" << m_data_a << std::endl;
		}
};
class B {
	private:
		int m_data_b = 2;
	public:
		virtual void fun_b(){
			std::cout << "B fun_b:" << m_data_b << std::endl;
		}
};

class C :public A, public B{
	private:
		int m_data = 3;
	public:
		void fun_a() override final {
			std::cout << "C fun_a:" << m_data << std::endl;
		}
		void fun_b() override final {
			std::cout << "C fun_b:" << m_data << std::endl;
		}
};

3.2,转换分析

类转换 运行结果 说明
“向上上转型”(即派生类指针或引用类型转换为其基类类型),本身就是安全的,尽管可以使用dynamic_cast进行转换,但这是没必要的, 普通的转换已经可以达到目的,毕竟使用dynamic_cast是需要开销的。
dynamic_cast转换失败返回0,pC是一个C派生类类型的空指针。而fun_a()和fun_b()都要访问成员变量,所以会段错误。如果fun_a()和fun_b()都不访问成员变量,还是可以正常执行的 对于“向下转型”有两种情况。 一种是基类指针所指对象是派生类类型的,这种转换是安全的; 另一种是基类指针所指对象为基类类型,在这种情况下dynamic_cast在运行时做检查,转换失败,返回结果为0;
编译出错。dynamic_cast将指向C派生类对象的基类类型指针pA装换成C派生类类型的指针后,又转换成了A基类类型的指针,用A基类类型的指针调用B基类的函数当然会出错
pC是一个指向C派生类类型的A基类类型指针。注意代码中注释有问题!
基类类型指针可以指向派生类类型指针
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值