cpp软件架构狮 2018-07-18 17:15:28
C语言中只能定义变量。
C++语言中可以定义变量和函数。同时C++语言中,struct 中所有变量和函数都是 "public" 权限
public:共有属性(修饰的成员变量和方法; 可以在类的内部和外部使用。)
private:私有属性(修饰的成员变量和方法,只能在类的内部使用,不能在类的外部使用)
protected:主要用于继承,保护属性(修饰的成员变量和方法; 可以在类的内部和继承的子类使用,不能在类的外部使用)
struct 中成员的默认权限为 public;
class 中成员的默认权限为 private;
1)构造函数:"名称和类名相同";"没有返回值 "。"可以有多个,进行函数重载"
在内存开辟之后调用构造函数。
2)无参构造函数和有参构造函数(又分为两种)
1.无参构造函数:定义对象的时候,对象后不能加括号。如:
class stu{
stu(){"无参构造函数"}};
stu st;(正确定义对象)。
如果加上括号: stu st(); 编译的时候不会报错,(因为编译器把它当作函数声明),运行的时候会报错。
2.有参构造函数:
"普通参数": 根据形参的类型和个数,也可以进行函数重载。
class Animal{ public: Animal(int age) { cout << "一个参数构造函数数字!" << endl; mName = "undefined"; mAge = age; } Animal(string name) { cout << "一个参数构造函数字母!" << endl; mName = name; mAge = 0; } Animal(string name,int age) { cout << "两个参数构造函数!" << endl; mName = name; mAge = age; } //拷贝(复制)构造函数用一个对象来初始化另一个对象 Animal(const Animal& animal) { //拷贝构造函数,形参必须是引用。否则会造成死循环,一直调用它本身。本质上成了递归调用本身。 cout << "拷贝构造函数!" << endl; mName = animal.mName; mAge = animal.mAge; } }
"拷贝参数":用一个对象来初始化另一个对象
它的形参必须是引用。如果是普通变量,就会造成本质上的递归调用本身;无意义。
3)析构函数:"名称=类名+"~""; "没有返回值";"没有参数"。"一个类只可以有一个析构函数"
在内存释放之前调用析构函数。
1) 括号法;
Animal animal1("smith"); //一个参数构造函数字母!
Animal animal2(20); //一个参数构造函数数字!
Animal animal3("John",30); //两个参数构造函数!
Animal animal4(animal3); //拷贝构造
2)显示调用构造函数(匿名对象调用拷贝构造的问题)
Animal("Smith",30); //匿名函数生命周期仅限于当前行;此行运行完后立即析构。
Animal animal5 = Animal(30); // 一个参数构造函数数字!;形参为普通变量
Animal animal5 = Animal("smith",90); 注意:/"两个参数构造函数!;拷贝构造。这行比上一行多了一个拷贝构造,是因为string容器的缘故。只有这时才会有拷贝构造"
Animal animal5(animal(30)); //一个参数构造函数数字!。
Animal animal5(animal(30,"smith")); "两个参数构造函数!;拷贝构造。" 原因同上,当不调用 string 参数时,它不会调用拷贝构造。"是由编译器处理的,具体处理方式不清楚"
"上面那两种情况,调不调用拷贝构造函数,主要看参数类型。===有string:就调拷贝构造函数;==== 没有string: 就不调拷贝构造函数===="
匿名对象如果有变量来接,它就是一个对象;"此时这个变量就相当于匿名对象的名称。"
匿名对象如果没有变量来接,他就是一个实例化对象。
Animal4("john",92); Animal(animal4); 此时当这两句在一起,编译器会报错,重定义。
3)等号法
Animal animal5 = 10; //不常用。调用一个函数构造函数
Animal animal5 = animal4l; “拷贝构造,常用
Animal animal5 = animal4l;
Animal animal5(animal4l);
1)对象以值传递的方式传递给函数参数。 void func(Animal animal2){ }; 用实参初始化形参,调用了拷贝构造函数
2)用一个对象初始化另一个对象。Animal animal5 = animal4l; 或者:Animal animal5(animal4l);
3)函数返回局部对象。(注意这里:debug模式和release模式不一样)。
debug模式下:会调用拷贝构造,打印两个地址也不相同。
release模式下,不会调用拷贝构造,打印的地址相同,编译器这里做了优化,直接把原来的对象返回回去了。
Animal MyBussiness() { //局部对象 Animal animal; //无参构造 cout << &animal << endl; return animal; //编译器先拷贝一份,然后返回。相当于返回一个匿名对象 } void test03() { Animal animal = MyBussiness(); cout << &animal << endl; }
默认情况下,编译器至少为我们写的类增加三个函数
1)默认构造函数(无参,函数体为空)
默认析构函数(无参,函数体为空)
默认拷贝构造函数,对类中非静态成员属性简单 "值"拷贝。
2) 如果用户定义了"拷贝构造函数",C++不会再提供"任何默认构造函数"。
3)如果用户定义了"普通构造,"C++"不会"再提供"默认无参构造",但是"会提供默认拷贝构造"。
4)在构造函数中调用构造函数是一个危险的行为。本质上:里面的构造函数相当于一个"匿名对象"。生命周期只有本行(没有变量接的情况下)。
"构造函数的初始化列表顺序:"
1)当一个类中组合了其他类的对象,先执行被组合的构造函数。
2)如果组合对象有多个,来自不同的类,根据定义的顺序进行构造函数的调用,而不是初始化列表的顺序。
3)“被组合对象的构造顺序:与定义顺序有关系,与初始化列表的顺序,没有关系”
4)若类成员中有 const 修饰,必须在对象初始化的时候,给 const 元素初始化。此时就用到了"初始化列表"。
"析构函数:与构造函数的调用顺序相反。"
class Person { public: Person(int a, int b) :_b(b),_a(b){} "初始化列表" //"深拷贝" Person(const Person &p1) { mstr = (char *)malloc(strlen(p1.mstr) + 1); "核心步骤" “会进行内存拷贝” strcpy(mstr, p1.mstr); _a = p1._a; _b = p1._b; } //"浅拷贝" Person(const Person &p1) { mstr = p1.mstr; "这里只会把一个对象的指针地址,赋给另一个对象的指针。";“不会进行内存拷贝” _a = p1._a; _b = p1._b; } void print_func() { cout << _a <<" " << _b << endl; } private: int _a; int _b; char *mstr; };
已知一个Print类,在该类的main()函数里执行语句 "Print a, b[2], *c;" 后;程序会自动调用该类的构造函数 4 次。
a会调用一次;b会调用两次;*c是空指针,没有开辟空间不会调用。
本页共140段,3650个字符,7342 Byte(字节)