上面的代码会打印“A”。
C++ 类指针定义的时候没有初始化的时候,居然可以安全的调用类内部的成员函数而不出错。
在网上查了一下:
 
初始化为NULL的类指针可以安全的调用不涉及类成员变量的类成员函数而不出错,但是如果类成员函数中调用了类成员变量则会出错,既然赋值为NULL的情况都可以使用,那么自然不初始化的类指针同样满足这类情况。
 
假设现在有一个简单的类定义如下:
class Test
{
public:
    void func(){cout << "hahaha" << endl;}
    int get(){return a+b;}
    Test():a(1),b(2){}
public:
    int a,b;
};
而之后编译器会自动将这个类转换成:
class Test
{
    int a,b;
};
void _test_func(Test * this);
int _test_get(Test* this);
........

类中的函数被编译器静态编译了,所有非虚函数(虚函数呢?别急,待会会解释到)都可以调用,因为函数地址编译期间已经确定。我们知道,类中的成员函数都是通过this指针调用成员变量的,编译器会将this指针作为默认参数传给类成员函数的,如myclass.function(int a,int b) --> function(&myclass,int a,int b)
添加main函数如下:
int main()
{
Test *p=NULL;
p->func();//正确,没有调用成员变量,没有使用空的this指针
p->get();//错误,this指针为空,通过this指针调用变量所以出错
return 0;
}
运行结果如上,没有调用成员变量的func()函数正确执行,调用了成员变量的get()函数错误。两者其实都传入了空的this指针,前者没出错仅仅是因为没有调用this指针,而后者调用了。(此时p-func()和p->get()等同于func(NULL),get(NULL)......)是对象指针为NULL,而调用成员函数的时候,函数地址是编译期间确定的,成员函数不通过对象指针(也即当前的p指针)去调用,对象指针仅仅作为参数传入函数然后去调用成员变量。
      好现在问题来了,如果是虚函数呢,因为虚函数要通过this指针计算vptr,然后找到vtable,然后dispatch。因为this指针为空,所以在找vtable时候就会coredump了。总之这类情况下,一切调用了this指针的函数都会出错,而完全不调用this指针的成员函数则没问题。
总结:任何时候定义指针的时候一定要初始化,这是良好的习惯,这个问题最初是由于当时写程序疏忽造成的,然而错有错着居然编译通过,所以当时一直没发现这个手误,现在追本溯源也算是对c++的内部机制有了更深的了解,不过也提示自己不能有侥幸心理,一定要养成良好的编程习惯,不管对于自己还是对于以后合作的伙伴都是一件好事。

C++类指针初始化的更多相关文章

  1. C++ 类的多态三(多态的原理--虚函数指针--子类虚函数指针初始化)

    //多态的原理--虚函数指针--子类虚函数指针初始化 #include<iostream> using namespace std; /* 多态的实现原理(有自己猜想部分) 基础知识: 类 ...

  2. C#多态;父类引用指向子类对象;new和override的区别;new、abstract、virtual、override,sealed关键字区别和使用代码示例;c#类的初始化顺序

    关于父类引用指向子类对象 例如: 有以下2个类 public class Father { public int age = 70; public static string name = " ...

  3. C++类构造函数初始化列表

    C++类构造函数初始化列表 构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式.例如: class CExample {public:     ...

  4. c++类与初始化,const

    --c++类与初始化,const --------------------------------2014/09/04 1. 类的定义(头文件.声明文件)看成类的外部接口,一般写成.h头文件. 2. ...

  5. C++类构造函数初始化列表(转)

    构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式.例如: { public:     int a;     float b;     //构 ...

  6. jvm(2)类的初始化(二)和实例化

    深入理解Java对象的创建过程:类的初始化与实例化 对象实例化内存分析: 对内存分配情况分析最常见的示例便是对象实例化: Object obj = new Object(); 这段代码的执行会涉及ja ...

  7. java类的初始化和构造函数

    本人小白一枚,看java类的初始化的时候好晕的说,我觉着书上尽管说的对.但总认为有些信息没说出来,没说清楚,看了好多文章博客的,如今有些感悟,来小写下总结,也算是为以后再次复习种个好果子. 先摘一下书 ...

  8. C++ 静态成员的类内初始化

    一般来说,关于C++类静态成员的初始化,并不会让人感到难以理解,但是提到C++ 静态成员的"类内初始化"那就容易迷糊了. 我们来看如下代码: //example.h #includ ...

  9. 为什么static成员必须在类外初始化,而不能在类的头文件中初始化

    为什么static成员必须在类外初始化 为什么静态成员不能在类内初始化 在C++中,类的静态成员(static member)必须在类内声明,在类外初始化,像下面这样.   class A { pri ...

随机推荐

  1. 文件操作,Io流。

    private void textBox1_TextChanged(object sender, EventArgs e) { } private void button1_Click(object ...

  2. mongodb备份、还原

    1.mongodb  备份 mongodump 命令可以使用可用的选项的列表. 此命令将仅备份指定的数据库,在指定的路径 语法 描述 示例 mongodump --host HOST_NAME --p ...

  3. 【NumPy学习指南】day4 多维数组的切片和索引

    ndarray支持在多维数组上的切片操作.为了方便起见,我们可以用一个省略号(...)来 表示遍历剩下的维度. (1) 举例来说,我们先用arange函数创建一个数组并改变其维度,使之变成一个三维数组 ...

  4. Mybatis配置多数据源

    一. Spring配置多数据源 二. Spring配置数据源 三. MultipleDataSource的实现 1: package com.wbl.modal; 2:  3: import org. ...

  5. SQL 基本编程

    定义变量 赋值 取值 分支语句 循环语句 定义变量 declare @变量   数据类型          //@必须带着  不然程序不知道变量是什么  不带@   电脑会报错 例如 declare ...

  6. HDU 4003 Find Metal Mineral (树形DP,经典)

    题意:给定一棵树图,n个节点,有边权,要派k<11个机器人从节点s出发,遍历所有的点,每当1只机器人经过1条边时就会花费该边的边权,边是可重复走的.问遍历完所有点的最小花费? 思路: 非常经典, ...

  7. mysql ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2 "No such file or directory")

    解决方案如下:

  8. C++通讯录

    C++通讯录1.0 历时一天,终于把通讯录写好了. 项目要求: 编写一个通讯录管理程序. 有一已存在的通讯录文件,数据内容为各联系人信息. 每个联系人信息的组成部分为: 姓名.电话号码和住址 等个人基 ...

  9. Codeforces Round #316 (Div. 2) B Simple Game 贪心

    贪心,如果m分成的两个区间长度不相等,那么选长的那个区间最接近m的位置,否则选m-1位置,特判一下n等于1的情况 #include<bits/stdc++.h> using namespa ...

  10. urllib基础-构造请求对象,设置用户代理User-Agent

    有的网页具有一些反爬机制,如:需要浏览器请求头中的User-Agent.User-Agent类似浏览器的身份证. 程序中不设置User-Agent.默认是Python-urllib/3.5.这样网站就 ...