1. 类函数中访问参数的私有变量
例如 String(constString &other)
{
m_data=other.x;//x是String类的私有成员
}
因为拷贝构造函数是放在本身这个类里的,而类中的函数可以访问这个类的对象的所有成员,当然包括私有成员了,访问控制是针对类而言的,而不是对象。
String(const String &other)
{
m_data=other.x;//x是String类的私有成员
}
引用参数对象也是String类的,所以没问题。
2. 函数声明当作对象定义
struct Test
{
Test(int){}
Test(){}
voidfun(){cout<<"func"<<endl;}
};
int main()
{
Test a(1);
Test b(); //此处是一个函数声明,返回值为Test类型,而不是对象定义!
Test b1; //对象定义
Test *c = new Test();
Test *d = new Test(2);
a.fun();
b.fun(); //error! 编译不过
c->fun();
d->fun();
system("pause");
return 1;
}
2.CMystring s4 = "abc";
// 等价于CMystring s4= CMystring("abc"); 但devc++中测试时,没有执行拷贝构造函数,只// 执行了CMystring( const char* str ); 原因是编译器对其优化了
class String
{
public:
String ( const char* p ); // 用C风格的字符串p作为初始化值
//…
}
String s1 = “hello”; //OK 隐式转换,等价于String s1 = String(”hello”)
类似问题解决:
#include <iostream>
using namespace std;
class A
{
public:
A(int i) : val(i){cout << "A():" << this << endl; };
int val;
A& operator=(const A& a )
{
cout<< "= func:" << &a << endl;
cout<< "= func:" << this << endl;
return*this;
}
A(const A&) :val(5){cout << "copy func"; }
};
int main()
{
A a = 3; // 本来是先调用 A(int )构造一个临时对象,然后 调用拷贝构造函数构造 a
// 这里是直接调用 A(int)构造 a,c++标准的原话,大意
// 为:当一个隐式声明的对象被拷贝到一个同类型的对象时,编译器可以选择跳过拷贝的过程而直接将拷贝的终
// 点对象作为构造的对象,而不必考虑因此带来的任何副作用。
cout << &a <<endl;
cout << a.val <<endl; // 输出3
system("pause");
return 1;
}
3. char* ,int,float隐式转化为bool类型
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
char *p = "jhk"; //char *p = "";也会输出1 char *p =NULL;会输出0
bool falg = p;
cout << falg;
system("pause");
return 1;
}
int main(int argc, const char *argv[])
{
int a = 1;
char * b = "wo";
float c = 1.1;
bool x;
x = a;
x = b;
x = c;
system("pause");
return 0;
}
总结:int,char*,float确实都可以隐式转化成bool而不会有任何警告,导致出现问题很不容易发现,这里在重载函数的时候确实需要万分注意。
4.枚举常量:
// 类CT的大小为4
class CT
{
public:
enum
{
SIZE1 = 100, // 枚举常量不占用内存空间,枚举它的隐含数据类型是int,不能表示浮点数,如PI = 3.1415
SIZE2 = 200
};
private:
int m_Int;
};
5. 常量问题:
const int cstInt = 0;
cout << sizeof(cstInt)<< endl;
//cstInt = 1; // 常量不能修改,编译时进行检测
cout << cstInt <<endl;
// int* pInt = &cstInt; //将编译通不过
int* pInt = (int*)&cstInt;// C++强制转换
*pInt = 3; // 这样将可以修改常量cstInt对应内存空间的值了,呵呵
cout << *pInt <<endl; // 输出3
cout << cstInt <<endl; // 为什么还是输出0呢?因为在编译时把所有用到cstInt的地方都改成了0,在后面改他的值是没有用的
//用普通变量的时候,汇编语句是
// mov eax,xxxValue
// push eax
// call xxxfunction
// 用const变量的时候是
// push 0
// call xxxfunction
6. 返回值以及extern问题:
// #include "test1.h" 使用test1头文件也可以
#include "test.h"
// .c文件,c++编译器将以c来编译此文件
int Add( int a, int b )
{
// 返回临时变量,如果int有构造函数,将调用构造函数,临时变量保存在此函数之外,节约了拷贝,但是此句将编译通不过,
// 因为当前文件是.c文件,而c语言中没有类的概念,所以也就没有构造函数的概念,所以此句通不过
//return int(a + b);
return a+b;
// return a+b; // 将把a+b的值拷贝到外部临时变量中
}
// 下面函数将编译通不过,因为extern是表明函数和全局变量作用范围的关键字
// int TestExtern()
// {
// extern int nInt;
// nInt = 10;
// int num = nInt;
// //int nInt = 1;
//
// return num;
// }
7. 释放类对象和内置类型的空间:
2.
int *p = new int[5];
//最好用delete[]p; 对于内置数据类型,如int char float等,可以用delete p代替delete []p;
delete p;
// 因为申请内存时,提供了确定的大小,释放时已经知道要释放多少内存,如本例是5个int大小
// 对于类,结构体等,释放数组时要使用delete []p,因为申请的内存在运行时可能会变化,如类中
// 若有char *p;一个数据变量,在运行中有p = new char[5];,其类内存变化了,要使用delete []p
// 告诉编译器释放的是一个数组,以便释放时调用其析构函数来释放动态申请的空间。
8. 一个内存分配导致的错误
#include <stdio.h>
#include <stdlib.h>
int main()
{
int m = 0;
int n = 3;
char pch[] = "";
scanf( "%s", pch);
printf( "%s\n\n",pch );
printf( "%d\n", n); // n不为3了
getchar();
getchar();
return 1;
}
解释:
pch[]没给大小,而且后面的赋值也是空串
它指向一个存不了数据的空间
即空间大小除了一个\0以为,没数据
pch指向的只有一个'\0'字符,输入时pch所指向的是堆栈中的内存,所以会覆盖n,导致n改变
#include <stdio.h>
void main()
{
int i,j,a[2] ;
for( i = 0 ; i <= 2 ; i++ )
scanf("%d",&a[i]); // 数组越界,但不会报错 a+3是j的地址
printf("%d\n",j); // j为最后输入的值
}