C语法(一)

容易混淆的几个注意点 2016/05/07

C++语法-容易混淆的几个注意点

1.指针常量 常量指针

*(指针)和 const(常量) 谁在前先读谁 *象征着地址,const象征着内容;谁在前面谁就不允许改变。

const int *p 常量指针 *p(内容/值)不能变 p(地址)可以变

int const *p 同上

int * const p 指针常量,p(地址)不能变 *p(内容/值)可以变

2.数组指针 指针数组 函数指针 指针函数

[]和()的优先级比星号(指针运算符)要高

理解为adj+n 先结合的就是n,前面的是adj

比如数组指针,指针是n(结果),先计算的是指针,再加上adj数组,得到 int(*p)[n]

int *p();		指针函数,无参数,返回int*
int (*p)();		函数指针,指向一个无参数,返回int的函数
int *p[n];		指针数组,数组的元素是 int* ,数组个数为n
int (*p)[n];	数组指针,指向一个数组,该数组的元素是int ,个数是n

3.地址的强制转换(a+1 ,&a+1)

a+1 跟&a+1的区别在于,看清楚是谁+1 (什么类型) 加1就是加上整个类型的偏移量

struct Test
{
   int Num;
   char *pcName;
   short sDate;
   char cha[2];
   short sBa[4];
}*p;

假设p 的值为0x100000。如下表表达式的值分别为多少?
p + 0x1 = 0x___ ?
(unsigned long)p + 0x1 = 0x___?
(unsigned int*)p + 0x1 = 0x___?

p + 0x1 的值为0x100000+sizof(Test)*0x1。至于此结构体的大小为20byte,前面的章节已经详细讲解过。所以p +0x1 的值为:0x100014。

(unsigned long)p + 0x1 的值呢?这里涉及到强制转换,将指针变量p 保存的值强制转换成无符号的长整型数。任何数值一旦被强制转换,其类型就改变了。所以这个表达式其实就是一个无符号的长整型数加上另一个整数。所以其值为:0x100001。

(unsigned int)p + 0x1 的值呢?这里的p 被强制转换成一个指向无符号整型的指针。所以其值为:0x100000+sizof(unsigned int)0x1,等于0x100004。


int main()
{
   int a[4]={1,2,3,4};
   int *ptr1=(int *)(&a+1);//指向a数组后面的内存单元,&a+1表示向后移16个存储单元
   int *ptr2=(int *)((int)a+1);//表示a的存储单元的地址增加一个字节
   printf("%x,%x",ptr1[-1],*ptr2);//ptr1[-1]其实指向的是a数组的最后一个单元,*ptr1则表示a数组的地址后移一个字节之后的4个连续存储单元所存储的值
   return 0;
}

ptr1:将&a+1 的值强制转换成int*类型,赋值给int* 类型的变量ptr,ptr1 肯定指到数组a 的下一个int 类型数据了。ptr1[-1]被解析成*(ptr1-1),即ptr1 往后退4 个byte。所以其值为0x4。

ptr2:按照上面的讲解,(int)a+1 的值是元素a[0]的第二个字节的地址。然后把这个地址强制转换成int类型的值赋给ptr2,也就是说ptr2 的值应该为元素a[0]的第二个字节开始的连续4 个byte 的内容。


检测大小端模式

小端:较的有效字节存放在较的存储器地址,较的有效字节存放在较的存储器地址。

大端:较的有效字节存放在较的存储器地址,较的有效字节存放在较的存储器地址。

int checkSystem()
{
  union check
  {
      int i;
      char ch;
  } c;
  c.i = 1;
  return (c.ch ==1);//如果当前系统为大端模式这个函数返回0;如果为小端模式,函数返回1。
}

如果当前系统为大端模式这个函数返回0;如果为小端模式,函数返回1。也就是说如果此函数的返回值为1 的话,ptr2 的值为0x2000000。如果此函数的返回值为0 的话,ptr2 的值为0x100。

4. 重写(覆盖)、重载、隐藏

C++中重载、重写(覆盖)和隐藏的区别

a、编译时多态性:通过重载函数实现

b、运行时多态性:通过虚函数实现。

重载:是指同一可访问区内被声明的几个具有不同参数列(参数的类型,个数,顺序不同)的同名函数,根据参数列表确定调用哪个函数,重载不关心函数返回类型

class A{
public:
void test(int i);
void test(double i);//overload
void test(int i, double j);//overload
void test(double i, int j);//overload
int test(int i);         //错误,非重载。注意重载不关心函数返回类型。
};

隐藏:是指派生类的函数屏蔽了与其同名的基类函数,注意只要同名函数,不管参数列表是否相同</kdb>,基类函数都会被隐藏。 `子类的fun已经隐藏了父类的fun函数` #include using namespace std;

class Base
{
	public:
	void fun(double ,int ){ cout << "Base::fun(double ,int )" << endl; }
};

class Derive : public Base
{
	public:
	void fun(int ){ cout << "Derive::fun(int )" << endl; }
};
int main()
{
	Derive pd;
	pd.fun(1);//Derive::fun(int )
	pb.fun(0.01, 1);//error C2660: “Derive::fun”: 函数不接受 2 个参数 
	system("pause");
	return 0;
} ---

重写(覆盖):是指派生类中存在重新定义的函数。其函数名,参数列表,返回值类型,所有都必须同基类中被重写的函数一致。只有函数体不同(花括号内),派生类调用时会调用派生类的重写函数,不会调用被重写函数。重写的基类中被重写的函数必须有virtual修饰。 #include

using namespace std;

class Base
{
public:
    virtual void fun(int i){ cout << "Base::fun(int) : " << i << endl;}
};

class Derived : public Base
{
public:
    virtual void fun(int i){ cout << "Derived::fun(int) : " << i << endl;}
};
int main()
{
    Base b;
    Base * pb = new Derived();
    pb->fun(3);//Derived::fun(int)
    system("pause");
    return 0;
} ---  完整示例
#include <iostream>

using namespace std;

class Base
{
public:
    virtual void f(float x){ cout << "Base::f(float) " << x << endl; }
    void g(float x){ cout << "Base::g(float) " << x << endl; }
    void h(float x){ cout << "Base::h(float) " << x << endl; }
};

class Derived : public Base
{
public:
    virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }
    void g(int x){ cout << "Derived::g(int) " << x << endl; }
    void h(float x){ cout << "Derived::h(float) " << x << endl; }
};

int main(void)
{
    Derived d;
    Base *pb = &d;
    Derived *pd = &d;
    // Good : behavior depends solely on type of the object
    pb->f(3.14f); //Derived::f(float) 3.14
    pd->f(3.14f); //Derived::f(float) 3.14

    // Bad : behavior depends on type of the pointer
    pb->g(3.14f); //Base::g(float) 3.14
    pd->g(3.14f); //Derived::g(int) 3

    // Bad : behavior depends on type of the pointer
    pb->h(3.14f); //Base::h(float) 3.14
    pd->h(3.14f); //Derived::h(float) 3.14

    system("pause");
    return 0;
} 1.函数Derived::f(float)`覆盖`了Base::f(float)。

2.函数Derived::g(int)隐藏了Base::g(float)而不是重载也不是覆盖(覆盖需要基类的函数有virtual)。

3.函数Derived::h(float)隐藏了Base::h(float)而不是覆盖也不是重载(重载需要在一个类里面的函数)。


5.聊聊多态

如果指针指向的函数为Virtual,则调用实际该指针指向的函数实参

如果指针指向的函数没有加上Virtual,则根据形参来调用。

#include <cstdlib>
#include <iostream>

using namespace std;

class Parent01
{
public:
    Parent01()
    {
        cout<<"Parent01:printf()..do"<<endl; 
    }
public:
    void test1()
    {    	
    	 cout<<"Parent01:void test1()"<<endl;
    }
	void test2()
    {    	
    	 cout<<"Parent01:void test2()"<<endl;
    }
    virtual void func()
    {
        cout<<"Parent01:void func()"<<endl;
    }

    virtual void func(int i)
    {
        cout<<"Parent01:void func(int i)"<<endl;
    }

    virtual void func(int i, int j)
    {
        cout<<"Parent01:void func(int i, int j)"<<endl;
    }
};

class Child01 : public Parent01
{

public:
 	void test1()
    {    	
    	 cout<<"Child:void test1()"<<endl;
    }
	void test2()
    {    	
    	 cout<<"Child:void test2()"<<endl;
    }
    void func(int i, int j)
    {
        cout<<"Child:void func(int i, int j)"<<" "<<i + j<<endl;
    }

    void func(int i, int j, int k)
    {
        cout<<"Child:void func(int i, int j, int k)"<<" "<<i + j + k<<endl;
    }
};

void run01(Parent01* p)
{
    p->func(1, 2); //根据实参来实现  func虚函数
}
void run02(Parent01* p)
{
    p->test1(); //根据形参来实现 Parent01  test1不是虚函数
}
void run03(Child01* p)
{
    p->test2();//根据形参来实现 Parent01  test1不是虚函数
}
void run04(Child01* p)
{
    p->func(1, 2); //根据实参来实现 func虚函数
}
int main()
{
    Parent01 p;//Parent01:printf()..do 

    p.func();//Parent01:void func()
    p.func(1);//Parent01:void func(int i)
    p.func(1, 2);//Parent01:void func(int i, int j)

    Child01 c;  //Parent01:printf()..do 
    //c.func();  //子类的函数被隐藏 
    c.Parent01::func(); //Parent01:void func()
    c.func(1, 2);//Child:void func(int i, int j) 3
    run01(&p);//Parent01:void func(int i, int j)
    run01(&c);//Child:void func(int i, int j) 3
    printf("--------------------\n");
    run02(&p);//Parent01:void test1()
    run02(&c);//Parent01:void test1()
    printf("--------------------\n");
   // run03(&p);//[Error]  invalid conversion from `Parent01*' to `Child01*'
    run03((Child01*)&p);  //如果强制转换还是调用了子类的方法   Child:void test2()  
    run03(&c);//Child:void test2()
    printf("--------------------\n");
    run04((Child01*)&p); //强制转换后 调用了父类的虚方法 Parent01:void func(int i, int j)
    run04(&c);//Child:void func(int i, int j) 3
	getchar(); 
    system("pause");
    return 0;
}


扫描关注我

(转载本站文章请注明作者和出处 Undefined

Post Directory