onlyou13

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

1、类和struct的区别
用class和struct关键字定义类的唯一差别在于默认访问权限:默认情况下,struct的成员为public(因此可以省略public关键字),而class的成员为private。

2、在C++中
每当函数返回时,都会清理栈。局部变量和函数参数存放在栈中。
只有到程序结束时候才会清理堆(java中自动清理),所以使用完堆内存时,程序员需要负责将其释放。如果在函数中预留堆中的内存,在函数返回后,该内存仍可用。当使用new关键字时候,程序会返回一个地址,因此只能用指针类型接收。注意用完之后要手动delete掉。

3、导致内存泄露的另一种情形是,没有释放指针指向的内存就直接给它重新赋值(重新new)

4、Teacher是一个类,
Teachert(name);//在栈中创建了一个对象
Teacher *t = new Teacher (name);//在堆中创建了一个对象
对于在栈中创建的Teacher对象,使用句点运算符(.)来访问其成员数据和成员函数;要访问对中的Teacher对象,必须对指针解引,并对指针指向的对象使用句点运算符。如(*t).XXX。鉴于比较繁琐,c++提供一种指向运算符(->),可以直接写为t->XXX

5、
具体地说如果出现以下几种情况,程序就会执行析构函数:
①如果在一个函数中定义了一个对象(它是自动局部对象),当这个函数被调用结束时,对象应该释放,在对象释放前自动执行析构函数。
②static局部对象在函数调用结束时对象并不释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用static局部对象的析构函数。
③如果定义了一个全局对象,则在程序的流程离开其作用域时(如main函数结束或调用exit函数) 时,调用该全局对象的析构函数。
④如果用new运算符动态地建立了一个对象,当用delete运算符释放该对象时,先调用该对象的析构函数。

6、c++中this指针,用->来指向对象。无需为创建和删除this指针操心,编译器负责这项工作。

7、const指针
const int * pOne;//pOne是指向整型常量的指针,不能修改指向的值
int * const pTwo ;//pTwo是指向整型的常量指针,不能修改指针的指向。
const int * const pThree; //pThree是一个指向整型常量的常量指针。

8、创建引用时,使用另一对象的名称来初始化它,对引用执行的任何操作实际上针对的就是目标。引用即对象的别名,在内存中没有地址,也不占用空间,引用一旦初始化就不能修改。

9、c++中按值传递和按引用传递
按值传递:安全,备份的修改不会更改原值
按引用传递:引用不创建备份,效率高,但会改变原值

10、不要返回不在作用域内的引用。引用始终是一个实际存在对象的别名,如果它指向的是空对像,那么程序是非法的。

11、不能对引用进行delete,因此函数的返回值如果为堆对象,且让引用接收,那么就无法回收对象。这样只能将引用再赋给指针来delete。

12、可以重载构造函数,但不能重载析构函数。析构函数的签名总是这样:名称为类名加~,且不接受任何参数。

13、一种特殊的写法,构造函数初始化默认参数(红色部分):

 1 #include<iostream>
 2 class Test
 3  {
 4 private :
 5      int a;
 6      int b;
 7 public:
 8      Test():
 9        a(1),b(2)
10        {
11 
12        }
13      Test(int a,int b)
14      {
15          this->a=a;
16          this->b=b;
17      }
18      int getA()
19      {
20          return this->a;
21      }
22      int getB()
23      {
24          return this->b;
25      }
26  };

14、拷贝构造函数
所有的拷贝构造函数都接受一个参数:指向类的引用。最好将该引用声明为常量,因为拷贝构造函数不能修改传入的对象。

15、不能对非NULL的指针进行delete,会报错。

16、如果未提供自己的拷贝构造函数,则C++提供一个默认拷贝构造函数,就像没有提供构造函数时,提供默认构造函数一样。
若用户没有定义拷贝构造函数,则编译器自动添加默认拷贝构造函数,称为浅拷贝。它只能完成基本类型数据类型(如int型变量)的拷贝,若类中有动态数组等数据类型, 浅拷贝就会出问题。即是说,浅拷贝有潜在危险(当类的数据成员都是基本类型数据类型时,它是安全的)。因此,在任何情况下,用户自定义拷贝构造函数是可取的。
出现指针成员变量的类中一定要自己写拷贝构造函数

17、成员方法加const表示该方法不会修改类成员。以下会报错:

1 void alterB() const
2  {
3      this -> b = this -> b + 1;
4  }

18、运算符重载的格式如下

returnType operatorsymbol (parameter list)
 {

 }
//如对类Count的++(前缀)的重载
Count& operator++ ()
{
     ++value;
    return *this;
}
//后缀++
Count operator++ (int)
{
    Count tmp (*this);
    ++value;
    return tmp;
}
//加法运算符+
Count operator+ (Count& c)
{
    return Count(this->value+c.value);
 } 
main()
{
    Count c1,c2,c3;
    c3=c1+c2;//这句话其实理解为c3=c1.operator+ (c2);即成员函数调用
}

19、复制运算符
例如:

Count c1(1);
 Count c2(2);
 c1 = c2;//此处不会调用拷贝构造函数,因为c1已经存在。

    上述赋值语句处会调用类中提供的默认赋值运算符。类中不仅提供了默认构造函数,默认析构函数,默认拷贝构造函数,还提供了默认复制运算符。
默认复制运算符与默认拷贝构造都有浅复制和深复制,浅复制只复制成员,导致两个对象执行同一个堆中区域。深复制则会分配内存。
可以重写复制运算符。假设类Count中有一个名为value的int指针

Count operator= (const Count& t)
 {
     if(this==t)
         return this;
     delete this -> value;
     value = new int ;
     *value = t.getValue();
     return *this;
 }

20、转换运算符
(1)内置类型变量赋值给一个用户定义类型对象

int i = 0;
 Count t = i;

只需要在Count类中提供一个带int 参数的构造方法即可
(2)用户定义类型对象赋值给内置类变量

Count t (2) ;
int i = t;

需要在Count类中指定转换运算符,如下(下划线部分):

class Count
 {
public:
     Count(int value){this->value=value;}
     operator unsigned int(){return value;}
private:
     int value;
 }

21、继承

class Parent
 {
     public:
             Parent(int value){this->value=value;}
     private:
             int value;
 };
class Child : public Parent
 {
     public:
             Child(int value):
             Parent(value),
             c('0')//不能将父类parent的value属性这样初始化。value初始化只能如上句调用父类构造函数、或者在下面的函数体内初始化
             {}
     private:
             char c;
 };

22、隐藏
在c++中,如果子类隐藏了父类的函数,则父类中的所有同名函数都会被隐藏!!!

#include<iostream>
class Parent
 {
public:
     Parent(){}
     Parent(int value){this->value=value;}
     ~Parent(){}
     Parent(Parent&){}
     void move(){std::cout<<"Parent moves "<<value<<" step!"<<std::endl;}
     void move(int n){std::cout<<"Parent moves "<<n<<" step!"<<std::endl;}

protected:
     int value;
 };
class Child: public Parent
 {
public:
     Child(){}
     Child(int value,int special):
     Parent(value),
     special(special)
     {

     }
     void move(){std::cout<<"Child moves "<<value<<" step!"<<std::endl;}
private:
     int special;
 };
void main()
 {
     Child *c=new Child(2,3);
     c->move(2);//error!!!因为父类中所有名字为move的函数都已经被隐藏,子类已经没有move(int)方法,但可以用父类调用
    Parent *p;
    p->move(3);//right!!!
}

在java中,如果子类隐藏了父类的函数,则父类中的其他同名函数不会被隐藏!!!下面是java代码

public class Parent {
     protected int value;
     public Parent() {
     }
     Parent(int value) {
         this.value = value;
     }
     public void move() {
         System.out.println("parent moves " + value + " steps!");
     }
     public void move(int n) {
         System.out.println("parent moves " + n + " steps!");
     }
 }
public class Child extends Parent {
     Child() {
         super();
     }
     Child(int value) {
         super(value);
     }
     public void move() {
         System.out.println("child moves " + value + " steps!");
     }
     public static void main(String[] args) {
         Child child=new Child(1);
         child.move(2);//right!!!
     }
 }

23、多态
要实现多态,就要声明为虚函数virtual,这与java是有区别的(java不需要声明virtual)。

class Parent
 {
     public:
             Parent(int value){this->value=value;}
             virtual void function(){}
     private:
             int value;
 };
class Child : public Parent
 {
     public:
             Child(int value):
             Parent(value),
             c('0')//不能将父类parent的value属性这样初始化。value只能如上句,或者在下面的函数体内初始化
             {}
             void function(){std::cout<<"test"<<std::endl;}
     private:
             char c;
 };

24、在多态的使用中,只有通过指针和引用进行调用时,才能发挥虚函数的魔力;按值传递对象时不能发挥虚函数魔力。按值传递只能够保留父类的方法,切除子类特有方法。

#include<iostream>
class Parent
 {
public:
     Parent(){}
     Parent(int value){this->value=value;}
     ~Parent(){}
     Parent(Parent&){}
     virtual void move(int n){std::cout<<"Parent moves "<<n<<" step!"<<std::endl;}
protected:
     int value;
 };
class Child: public Parent
 {
public:
     Child(){}
     Child(int value,int special):
     Parent(value),
     special(special)
     {

     }
     void move(int n){std::cout<<"Child moves "<<n<<" step!"<<std::endl;}
private:
     int special;
 };
void main()
 {
     Parent *p = new Child(1,1);
     p->move(1);//输出child moves 1 step!
     Parent& p1 = *p;
     p1.move(1);//输出child moves 1 step!
     Parent p2 = *p;
     p2.move(1);//输出Parent moves 1 step!,即子类的方法被切除,调用父类方法
     delete p;
 }

25、 如果将基类指针赋给子类,就用到了dynamic_cast,它确保转换是安全的。在运行阶段检查基类指针,如果可以转换,就转化为子类指针,如果不能,子类指针为空NULL。

26、C++中用纯虚函数来支持抽象数据类型ADT,抽象类和函数。java中用abstract关键字。
任何包含一个或多个纯虚函数的类都是ADT,不能对其实例化,试图这样做将导致编译错误。
a、不能创建这个类的对象,只能从其派生
b、务必重写从这个类继承的纯虚函数

#include<iostream>
class Parent
 {
public:
     Parent(){}
     Parent(int value){this->value=value;}
     ~Parent(){std::cout<<"destructor"<<std::endl;}
     Parent(Parent&){}
     virtual void move()=0;
protected:
     int value;
 };
class Child: public Parent
 {
public:
     Child(){}
     Child(int value,int special):
     Parent(value),
     special(special)
     {

     }
     void move(){std::cout<<"Child moves "<<value<<" step!"<<std::endl;}
private:
     int special;
 };
void main()
 {
     Parent *p = new Parent(1);//error!!!,不能创建ADT的对象
     Child *c = new Child(1,1);//子类实现了纯虚函数,可以创建对象
     c->move();
 }

27、不要忘记给静态成员变量赋初值。不像java,变量可以直接在类中声明处赋值,c++中的变量赋值不能在类中声明处赋初值

#include<iostream>
class Parent
 {
public:
     Parent(){}
     Parent(int value){this->value=value;}
     ~Parent(){}
     Parent(Parent&){}
     int value;
     static int num;
 };
int Parent::num=0;

28、要将私有成员或函数暴露给另一个类,必须将其声明为友元类,友元关系不能传递,不能继承,也不可交换,将Class1声明为Class2的友元并不能让Class2成为Class1的友元。有时候不想将友元访问权限赋予整个类,为此,可以将成员函数而不是整个类声明为友元。
友元函数:友元函数的声明可以放在类的私有部分,也可以放在公有部分,它们是没有区别的,都说明是该类的一个友元函数

#include<iostream>
class Parent
 {
public:
     Parent(){}
     Parent(int value){this->value=value;}
     ~Parent(){}
     Parent(Parent&){}
    friend void getValue(Parent& p);
private:
     int value;
 };
void getValue(Parent& p)//不需要加Parent::,因为友元函数不属于该类
 {
     std::cout<< p.value<<std::endl;
 }
void main()
 {
   Parent p(2);
   getValue(p);//友元函数不属于类,直接调用,无需对象表示
 }

友元类:一个类能够作另一个类的友元。当一个类作为另一个类的友元时,这就意味着这个类的任何成员函数都是另一个类的友元函数。
以下语句说明类B是类A的友元类:

#include<iostream>
class A
 {
public:
     A(){}
     A(int value){this->value=value;}
     ~A(){}
     A(A&){}
    friend class B;
private:
     int value;
 };
class B
 {
public:
     B(){}
     ~B(){}
     B(B&){}
     void getValue(A& a)
     {
         std::cout<<a.value<<std::endl;
     }
 };
void main()
 {
     A a(2);
     B b;
     b.getValue(a);
 }

经过以上说明后,类B的所有成员函数都是类A的友元函数,能存取类A的私有成员和保护成员。

29、函数指针
可以声明指向函数的指针,其实函数名就是指向函数的常量指针,就像数组名是指向数组第一个元素的常量指针一样。

#include<iostream>

void add(int a, int b)
 {
     std::cout<< a+b <<std::endl;
 }
void subtract(int a, int b)
 {
     std::cout<< a-b <<std::endl;
 }

void main()
 {
     void (*pFunc) (int, int);
     pFunc=add;//给函数指针赋值,使其指向add函数
     pFunc(2,1);//赋值之后调用
     pFunc=subtract;
     pFunc(2,1);
 }

30、将函数指针作为参数传递

#include<iostream>

void add(int a, int b)
 {
     std::cout<< a+b <<std::endl;
 }
void subtract(int a, int b)
 {
     std::cout<< a-b <<std::endl;
 }
void printValue(void (*func)(int, int) , int a, int b)//函数指针作为参数
 {
     func(a,b);
 }
void main()
 {
     void (*pFunc) (int, int);//函数指针声明
     pFunc=add;//函数指针赋值
     printValue(pFunc,2,1);//函数指针作为参数传递
     pFunc=subtract;
     printValue(pFunc,2,1);
 }

31、空指针常量:使用指针时候一定要给它赋值,,未初始化的指针可能指向内存的任何位置,这就做野指针。为了避免这种威胁,创建时候应该将空值(0或者NULL)赋给指针。但这会在函数重载的时候造成一定麻烦,比如一个接收字符型指针或整数作为参数:
void func(char *);
void func(int);
若调用时候传递一个空指针,则调用void func(int),这不符合设计人员本意。

32、函数模板

#include<iostream>

template<class T>

void swap(T& a, T& b)
 {
     T tmp;
     tmp=a;
     a=b;
     b=tmp;
 }

void main()
 {
     int a=1,b=2;
     swap(a,b);
     std::cout<<"a="<<a<<", b="<<b<<std::endl;
 }

33、类模板

#include<iostream>

template<class T>
class A
 {
public:
     A(T value)
     {
         this->value=value;
     }
     T getValue()
     {
         return value;
     }
private:
     T value;
  
 };

void main()
 {
     A<int> a(2);

     std::cout<<a.getValue()<<std::endl;
 }

 

本文转载自http://blog.csdn.net/dreamrealised/article/details/16855573,感谢原作者的精心总结!!

posted on 2013-11-22 15:25  onlyou13  阅读(107)  评论(0编辑  收藏  举报