新手勇闯C++

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:引入虚基类表,存放各个虚基类的偏移

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值