c++类和对象(一)

1.类成员函数的定义和实现可以分开写

//定义一个类
class ABC
{
    public:
        void hello(void);
};
//实现类方法
void ABC::hello()
{
    cout<<"hello world"<<endl;
};

2.类成员的可访问范围

  • private:私有成员,只能在成员函数内部访问
  • protected:保护成员
  • public:公有成员,可以在任何地方访问
  1. 如果属性和方法的权限是缺省的,则默认是私有
  2. 在类的成员函数内部:
  3. 可以访问当前对象的全部属性、方法,可以访问同类对象的全部属性、方法
  4. 在类的成员函数以外,只能访问对象的公有方法
  5. 设置私有成员的机制,叫做“隐藏”
  6. “隐藏”的目的是强制对成员变量的访问一定要通过成员函数进行,那么以后成员变量的类型等属性修改后,只需要更改成员函数即可。否则所有直接访问成员变量的语句都要修改。

3.成员函数的重载和参数缺省
使用缺省参数要避免重载时候的二义性

class ABC
{
    public:
        void hello(void);
        void hello(std::string name, int age=20);
};
void ABC::hello()
{
    cout<<"hello world"<<endl;
};
void ABC::hello(std::string name, int age)
{
    cout<<"hello world "<<name<<",age="<<age<<endl;
};
int main(void)
{
    ABC obj;
    obj.hello("jack");  //输出结果  hello world jack,age=20
    //system("pause");
    return 0;
}

4.构造函数

  1. 它是成员函数的一种
  2. 名字与类名相同,可以有参数,不能有返回值(void也不用写)
  3. 作用是对象初始化,如给成员变量赋值
  4. 如果没有定义构造函数,则编译器自动生成一个无参的构造函数,不进行任何操作
  5. 如果定义了构造函数,则编译器不生成默认的无参数的构造函数
  6. 对象生成时,构造函数被自动调用。对象一旦生成,就再也不能调用构造函数
  7. 构造函数可以重载
  8. 构造函数执行必要的初始化工作,有了构造函数,就不必专门再写初始化函数
  9. 有时对象没有初始化就被调用,会导致程序出错
class  Test {
    public:
        Test( int n) { }                //(1)
        Test( int n, int m) { }         //(2) 
        Test() { }                      //(3)
};
Test  array1[3] = { 1, Test(1,2) };					// 三个元素分别用(1),(2),(3)初始化
Test  array2[3] = { Test(2,3), Test(1,2) , 1};		// 三个元素分别用(2),(2),(1)初始化
Test  * pArray[3] = { new Test(4), new Test(1,2) };	//两个元素分别用(1),(2) 初始化

5.复制构造函数
只有一个参数,即对同类对象的引用,不能是对象
形如:X::X(X&) 或者 X::X(const X&),二者选一,后者能以常量对象作为参数
如果没有定义复制构造函数,那么编译器生成默认复制构造函数,默认的赋值构造函数完成赋值功能

//默认的复制构造函数
class Complex {
    private :
        double real,imag;
};
Complex c1;     // 调用缺省无参构造函数
Complex c2(c1); // 调用缺省的复制构造函数 ,将 c2 初始化成和 c1 一样
//如果自定义复制构造函数,则默认的复制构造函数不存在
class Complex {
    public :
        double real,imag ;
    Complex(){ } 
    Complex( const Complex & c ) 
    {
        real = c.real;
        imag = c.imag;
        cout << “Copy Constructor called”;
    }
};
Complex c1 ;
Complex c2(c1);

复制构造函数起作用的三种情况

  1. 当用一个对象去初始化同类的另一个对象时
Complex c2(c1);    
Complex c2 = c1;    //用复制构造函数初始化,不是赋值语句
  1. 如果某函数有一个参数是类A的对象,那么该函数被调用时,类A的复制构造函数将被调用
  2. 如果函数的返回值是类A的对象时,则函数返回时,A的复制构造函数将被调用
class A
{
    public:
        int v;
        A() {};                     //空的构造函数
        A(int value) {v = value};   //有一个参数的构造函数
        A( A & a) {                 //复制构造函数
            cout<<"Copy constructor called"<<endl;
        }
};
void Func (A a1){ }
A Func (){
    A b(4);
    return b;
}
int main(){
    A a2;
    Func (a2);              //a2是实参,a1是形参,所以参数传递时,需要调用复制构造函数
    cout<<Func().v<<endl;   //打印返回值对象的属性
    return 0;
}

注意,对象间的赋值并不导致复制构造函数被调用

class A...;
A a,b;  //创建了2个对象
A c(a); //通过拷贝构造函数来创建新的对象
a = c;  //仅仅只是完成对象属性之间的赋值(浅拷贝),不会调用拷贝构造函数
//需要注意指针的赋值会指向同一款区域,某个对象释放空间后,这个指针将变成野指针

6.常量引用参数的使用

void fun(A obj)
{
    cout<<"fun"<<endl;
}

这样的函数,调用时会调用复制构造函数,开销比较大
可以使用A&引用类型作为参数,如果不希望值被改变,还可以加const

void fun(const A& obj)
{
    cout<<"fun"<<endl;
}

7.类型转换构造函数
定义转换构造函数的目的是实现类型的自动转换
只有一个参数,而且不是复制构造函数的构造函数,一般可以看做是转换构造函数
当需要的时候,编译系统会自动调用转换构造函数,建立一个无名的临时对象

class Complex {
public:
    double real, imag;
    Complex( int i) { // 类型转换构造函数
        cout << "IntConstructor called"<<endl;
        real = i; imag 0; 
    }
    Complex(double r,i) {real = r; imag i; } 
};
int main ()
{
    Complex c1(7,8);
    Complex c2 = 12;
    c1 = 9;     // 9被自动转换成一个临时 Complex 对象,然后赋值给c1
    cout << c1.real "," imag endl; 
    return 0;
}

8.析构函数
名字与类名相同,在前面加~,没有参数和返回值,一个类最多只能有一个析构函数
析构函数在对象消亡时自动调用,用以善后工作,例如空间的释放
如果定义类时缺省析构函数,则编译器自动生成析构函数,里面啥也不做
如果定义了析构函数,则编译器不再自动生成缺省的析构函数
delete运算符会引起析构函数的调用

class A
{
    public:
        int value;
    public:
        ~A(){cout<<"distory"<<endl;}
};
//main函数运行,只会打印一次,new分配的空间,不delete是不会调用析构函数的
int main(void)
{
    A * p = new A;  //程序结束时不会调用析构函数 
    A a;            //程序结束时会调用析构函数 
    return 0;
}

猜你喜欢

转载自blog.csdn.net/whitefish520/article/details/100814859
今日推荐