C++学习(21)

来源:互联网 发布:手机蓝牙麦克风软件 编辑:程序博客网 时间:2024/05/19 13:26

1、

#include<iostream>using namespace std;void foobar(int a,int*b,int **c) {       int *p=&a;       *p=101;       *c=b;       b=p;}int main(){       int a=1;       int b=2;       int c=3;       int *p=&c;       foobar(a,&b,&p);       cout<<a<<""<<b<<" "<<c<<""<<*p<<endl;       return 0;}

注意:改变一个数据需要一级指针,改变一个一级指针需要二级指针,引用就是一个别名;

 

函数foobar中的a是按值传递,因此在函数中的修改不会引起主函数中的变化。

函数中b传递的是主函数中b的指针,语句b = p ,其中p指向的是函数foobar内局部变量a的地址,让传递过去的指针换了指向的数据,原来指向的数据(主函数中的b)不会有影响。如果这里是*b = *p那么主函数中的b也要相应变化。

函数中的c传递的是双重指针,*c = b,也就是让主函数中的p指针指向了主函数中的b的地址在函数foobar中对指针的变化没有影响到主函数,只是让双重指针更换了指向而已。

说了半天上个图吧,比较直接。说明:值用=表示,指针用:表示,双重指针用::

 

2、

#include<iostream>#include<string.h>using namespace std;class A {}; class B{       char ch;       int x;}; class C{       public:              void Print(void) {}}; class D {       public:              virtual void Print(void) {              }}; int main(){       cout<<sizeof(A)<<""<<sizeof(B)<<" "<<sizeof(C)<<""<<sizeof(D)<<endl;       return 0;}


分析:类A空类型的实例虽然不包含任何信息,但是必须在内存中占一定的空间,否则无法使用这些实例,一般都是1;

类B因为内存对齐所以为8,

类C里面虽然有函数,但是只需要知道函数的地址即可,而这些函数的地址只与类型相关,而与类型的实例无关,编译器不会因为函数而在内存中多添加任何的额外信息.所以还是1;

类D因有虚函数,C++的编译器一旦发现一个类型中有虚函数,就会为该类型生成虚函数表,在该类型的每一个实例中添加一个指向虚函数表的指针.因为多了一个指针,所以在32位机器为4,64位机器为8

 

注意:空类编译器会将sizeof()的值变为1;
类的大小只与非静态成员和虚函数的大小有关,而与其他普通函数成员无关,与构造函数析构函数也无关。

 

3、设p是指针变量,语句p=NULL;等价于 p=0;

分析:‘\0’的ASCII码为0,所以NULL等效于0

 

4、有函数定义:

void test(int a) {}

       void test (float a) {}

则以下调用错误的:D

A test(1);         Btest(‘c’);      C test(2+’d’);          D test(0.5);

分析:编译器会提示参数不匹配,但是不匹配的原因是:类型转换只能从下往上自动转换,而不能自动从上往下转换。

0.5默认是double类型,既不能转换成float类型,也不能转换成int类型。故会提示参数不匹配。

 

5、若有定义

Typedef char T[10];T * a;

等价于 char*a[10];

A char a[10];          B char (*a)[10];            Cchar *a;   D char *a[10];

 

分析:a到底是指向一个10个数据的指针,还是一个指向10个指针的数组;

我认为偏向前者

看分析:

T b;相当于 char b[10];

相信大家对这个没啥意见吧

那么,T *a;也就是一个指针a指向了一片空间,空间连续,并且以T为基本单位;

 

来看D答案 : char *a [ 10 ]

里面的10指的是10个T类型的指针,

而typedef char T[10] 里面的10指的是10个char数值

两个10之间没啥关系;

T *a也没有告诉我们就必须申请10个指向T类型的指针

T *a只是告诉我们声明了一个a指针,指向一片地方,这片地方都是T类型的数据而已

这就像是int *a = new int[],

我们有一个指针a,以int类型为单位移动,int默认4字节移动(32位cpu)

只不过这里T是默认10个字节移动

 

 

B答案: char ( *a) [ 10 ] ; (大写A改成小写)

声明了一个指针,指针每次移动都是以T为单位的 ,符合!

***********************// edition 1typedef char T[10];int main() {T *a;char (*b)[10];a = b;}************************// edition 2typedef char T[10];int main() {T *a;char *b[10];a = b;} 


6、对于派生类的构造函数,在定义对象时构造函数的执行顺序:

基类构造函数->成员对象构造函数->派生类本身的构造函数。

分析:1.类的构造函数可能使用类的对象成员,因此类的对象成员→类的构造函数

2.派生类的构造函数可能使用父类的对象成员,因此基类的构造函数→派生类的构造函数

3.析构和构造刚好相反~

 

补充:

当派生类中不含对象成员时

       ·在创建派生类对象时,构造函数的执行顺序是:基类的构造函数→派生类的构造函数;

       ·在撤消派生类对象时,析构函数的执行顺序是:派生类的构造函数→基类的构造函数。

当派生类中含有对象成员时

       ·在定义派生类对象时,构造函数的执行顺序:基类的构造函数→对象成员的构造函数→派生类的构造函数;

       ·在撤消派生类对象时,析构函数的执行顺序:派生类的构造函数→对象成员的构造函数→基类的构造函数。

 

7公用(public):访问权限最高;除派生类外,外部函数也可以直接访问(无论是成员变量还是成员函数)。

私有(private):访问权限最低;只能是该类内部函数互相调用,派生类、外部函数都不能访问。

保护(protect):访问权限中间;该类内部函数、派生类都能访问,外部类、外部函数不能访问 

 

我们这样来记会更加容易一些,在继承时:

1、不管采用哪种形式(public, protectedprivate),基类中的私有成员都不可以被继承;如果非要在派生类中使用基类的私有成员,可以有两种方法:一是使用属性,二是使用友元类或友元函数。

2、如果采用public形式,则基类除了私有成员的其它所有都被原样的继承到派生类中;即在基类中是public的,在派生类中还是public的,在基类中是protected的,在派生类中还是protected的。

3、如果采用protected形式,则基类中除了私有成员的其它说有都被以protected的形式继承到派生类中。

C++中的继承方式有:

publicprivateprotected三种(它们直接影响到派生类的成员、及其对象对基类成员访问的规则)。

1public(公有继承):继承时保持基类中各成员属性不变,并且基类中private成员被隐藏。派生类的成员只能访问基类中的public/protected成员,而不能访问private成员;派生类的对象只能访问基类中的public成员。

2private(私有继承):继承时基类中各成员属性均变为private,并且基类中private成员被隐藏。派生类的成员也只能访问基类中的public/protected成员,而不能访问private成员;派生类的对象不能访问基类中的任何的成员。

3protected(保护性继承):继承时基类中各成员属性均变为protected,并且基类中private成员被隐藏。派生类的成员只能访问基类中的public/protected成员,而不能访问private成员;派生类的对象不能访问基类中的任何的成员。

 

8

#define INT_PTR int;

INT_PTR a,b;

在进行替换的时候,是这个样子:

int* a,b;

也就是说a是指针类型,而b是整型。

typedef int*int_ptr;这是合适的类型定义。定义一种类型的别名,而不是简单的宏替换,还可以用在结构体的定义中。