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. 重写(覆盖)、重载、隐藏
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
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)