1.const char* 与 char*有什么区别
对指针所指向的数据的修改能力不一样
char*:
这是一个指向字符的指针,没有const修饰符。
你可以通过这个指针来修改它所指向的字符数据。
例如,你可以使用这样的代码来修改一个字符数组中的字符:
char str[] = "Hello";
char* ptr = str;
*ptr = 'h'; // 将第一个字符从'H'改为'h'
const char*:
这是一个指向字符的常量指针,即你不能通过这个指针来修改它所指向的字符数据。
但请注意,这并不意味着指针本身(即存储地址的变量)是常量;它只是说你不能通过这个指针来修改它所指向的数据。
你可以使用这个指针来读取字符数据,但不能修改它。
例如,以下代码是合法的,因为它只是读取数据:
const char* ptr = "Hello";
char ch = *ptr; // 获取第一个字符'H'
但以下代码是不合法的,因为它试图修改一个字符串字面量(这通常存储在只读内存段中):
const char* ptr = "Hello";
*ptr = 'h'; // 错误:不能修改字符串字面量
然而,你可以将const char*指针指向一个非const的字符数组,但你仍然不能通过这个指针来修改数组中的数据:
char str[] = "Hello";
const char* ptr = str;
// *ptr = 'h'; // 错误:尽管str不是const,但ptr是const char*类型
总的来说,const char和char的主要区别在于它们对指针所指向的数据的修改能力。选择使用哪一个应该基于你是否需要或想要通过指针来修改数据。
当我写一个函数void getname(char* name),main函数调用 stu.getname(“xiaoming”)是错的,为了代码的安全性,传递的是字符串字面量作为参数,字符串字面量本身无法修改,使用const char类型,,所有char name及其相关函数全部改为 const char* name
2.C++基类与派生类构造函数调用
学习别人的博客:原文链接:https://blog.csdn.net/qq_41854911/article/details/119393012
基类的成员函数可以被继承,可以通过派生类的对象访问,但这仅仅指的是普通的成员函数,类的构造函数不能被继承。例如:
Student::Student(char *name, int age, float score){
People(name, age);
m_score = score;
}
是错误的,基类的构造函数只能放在函数头部
Student::Student(char *name, int age, float score): People(name, age), m_score(score){ }
TIPS:关于析构函数:
它在对象的生命周期结束时被自动调用。析构函数的主要目的是执行一些清理操作,如释放对象在生命周期中分配的资源(如内存、文件句柄、数据库连接等)
3.借助指针突破访问权限的限制,访问private、protected属性的成员变量
C++ 不允许通过对象来访问 private、protected 属性的成员变量,无论对象是整数还是指针,但是可以通过指针突破访问权限限制,访问private、protected属性的成员变量
int b = p->m_b;
此时编译器内部会发生类似下面的转换:
int b = (int)( (int)p + sizeof(int) );
p 是对象 obj 的指针,(int)p将指针转换为一个整数,这样才能进行加法运算;sizeof(int)用来计算 m_b 的偏移;(int)p + sizeof(int)得到的就是 m_b 的地址,不过因为此时是int类型,所以还需要强制转换为int 类型;开头的用来获取地址上的数据。
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/10092e861bd24bdc84e4557a14c4c3d3.pn
#include <iostream>
using namespace std;
class A{
public:
A(int a, int b, int c);
private:
int m_a;
int m_b;
int m_c;
};
A::A(int a, int b, int c): m_a(a), m_b(b), m_c(c){ }
int main(){
A obj(10, 20, 30);
int a1 = *(int*)&obj;
int b = *(int*)( (int)&obj + sizeof(int) );
A *p = new A(40, 50, 60);
int a2 = *(int*)p;
int c = *(int*)( (int)p + sizeof(int)*2 );
cout<<"a1="<<a1<<", a2="<<a2<<", b="<<b<<", c="<<c<<endl;
return 0;
}
TIPS:不知道为什么实现不了,报了未经处理处理的异常,读取访问权限的冲突
4.虚基类与虚继承
多继承命名容易存在二义性,C++提出虚继承,使得间接基类继承的成员函数只保留一个
class B: virtual public A{ //虚继承
虚继承的目的是让某个类做出声明,承诺愿意共享它的基类。其中,这个被共享的基类就称为虚基类(Virtual Base Class)不论虚基类在继承体系中出现了多少次,在派生类中都只包含一份虚基类的成员。
iostream使用的就是虚继承
同时,最终派生类的构造函数必须要调用虚基类的构造函数,传统的继承不需要调用间接继承的构造函数,只需要调用直接继承的构造函数
D::D(int a, int b, int c, int d): A(a), B(90, b), C(100, c), m_d(d){ }
在最终派生类 D 的构造函数中,除了调用 B 和 C 的构造函数,还调用了 A 的构造函数,这说明 D 不但要负责初始化直接基类 B 和 C,还要负责初始化间接基类 A。
在构造函数执行顺序时,编译器会优先调用虚基类的构造函数
虚继承下的内存模型:会先存放普通继承的成员变量,然后是自身的成员变量,最后是虚继承的成员变量,这样虚继承的成员变量位置是不固定的,如何访问虚继承的成员变量?
1.cfront方法:cfront编译器在派生类对象中安插指针,指向虚基类的起始位置
2.VC:引入虚基类表,存放各个虚基类的偏移