Почему C ++ может использовать неинициализированные переменные-члены (ссылка или указатель * NOT value copy *) для инициализации переменных-членов своего родительского класса - PullRequest
0 голосов
/ 26 апреля 2018

У меня есть два вопроса об инициализации переменных-членов в C ++.

  1. Почему код explicit Apple(const char* name) :Fruits(&_name) работает, когда строительная функция Fruits определяется как explicit Fruits(std::string* f_n) :f_name_(f_n) (или когда указатели в этих кодах заменяются ссылочными)?

  2. Распределяются ли переменные-члены производного класса после или перед переменными-членами его подосновного класса?

см. Код ниже.

// Apple.h c++
#pragma once
#include<iostream>
#include<cstring>
#include<string>

class Plant {
public:
    Plant() {
        std::cout << "Plant construction function called." << std::endl;
    }
    inline void show() {
        std::cout << "name:" << s_name_ << std::endl;
    }

    void Init() {
        std::cout << "Init assign value called." << std::endl;
        s_name_ = this->getName();
    }
    virtual ~Plant() {
        std::cout << "Plant deconstruction function called." << std::endl;
    }
private:
    std::string s_name_;

protected:
    virtual std::string getName() = 0;
};

class Fruits: public Plant{
public:
    explicit Fruits(std::string* f_n) :f_name_(f_n) {
        std::cout << "Fruits construction function called."<< std::endl;
    }
    virtual ~Fruits() {
        std::cout << "Fruits deconstruction function called." << std::endl;
    }
protected:
    std::string getName() override {
        std::cout << "getName() function called." << std::endl; 
        return *f_name_;
    }
private:
    std::string* f_name_;
};

class Apple:public Fruits {
private:
    std::string _name;
public:
    explicit Apple(const char* name) :Fruits(&_name) {
        _name = name;
        std::cout << "Apple constuction function called."<< std::endl;
        Plant::Init();
    }

    ~Apple() {
        std::cout << "Apple deconstruction function called." << std::endl;
    }
};

// main.cpp
#include<iostream>
#include "Apple.h"
using namespace std;

int main() {
    {
        cout << "test1:" << endl;
        Apple t1("Apple1");
        t1.show();
    }
    cin.get();

    return 0;
}

Ответы [ 3 ]

0 голосов
/ 26 апреля 2018

Почему код явно Apple (const char * name): Fruits (& _ name) работает, когда функция построения Fruits определена как явная Fruits (std :: string * f_n): f_name_ (f_n) (или когда указатели в этих кодах заменены ссылками)?

Вы передаете адрес переменной-члена _name, которая имеет тип std::string, поэтому она хорошо компилируется и explicit не имеет к этому отношения. Обратите внимание, что вы играете в очень опасную игру здесь, если вы попытаетесь разыменовать этот указатель внутри конструктора Fruits, вы получите UB.

Распределяются ли переменные-члены производного класса после или перед переменными-членами своего базового класса?

Ваш вопрос показывает, что вы не понимаете, как это работает. Производный класс - это объект, который находится в sizeof(typename) памяти, которая включает базовый объект и все переменные-члены, добавляемые производными, если таковые имеются. Когда память выделяется для него, она выделяется сразу для всего объекта, а не по частям. Другая проблема - порядок инициализации - хотя выделенная память объектов инициализируется от базового к производному, поэтому, если вы попытаетесь получить доступ к объектам производного класса в конструкторе базового класса, вы получите UB, как если бы вы попытались получить доступ к неинициализированному объекту.

0 голосов
/ 26 апреля 2018

1.Почему в коде явно Apple (const char * name): Fruits (& _ name) работает, когда строительная функция Fruits определена как явная Фрукты (std :: string * f_n): f_name_ (f_n) (или когда указатели на них коды заменяются ссылками)?

ваш explicit Fruits(std::string* f_n) хочет указатель на std :: string _name является членом Apple типа std :: string, поэтому взятие адреса _name приведёт к нужному std :: string *.

  1. Распределяются ли переменные-члены производного класса после или перед переменными-членами своего базового класса?

Сначала инициализируется родительский класс, после этого производного класса. так что в вашем случае передача Fruits(&_name) здесь:

explicit Apple(const char* name) :Fruits(&_name) {
        _name = name;

означает, что _name не инициализирован в данный момент, он будет инициализирован после завершения работы конструктора Fruits

0 голосов
/ 26 апреля 2018

Потому что это просто добавление конструктора с другой подписью в Apple. Это не имеет ничего общего с фруктами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...